/* license-start * * Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details, at <http://www.gnu.org/licenses/>. * * Contributors: * Crispico - Initial API and implementation * * license-end */ package org.flowerplatform.editor; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.flowerplatform.blazeds.custom_serialization.CustomSerializationDescriptor; import org.flowerplatform.common.plugin.AbstractFlowerJavaPlugin; import org.flowerplatform.communication.CommunicationPlugin; import org.flowerplatform.editor.file.IFileAccessController; import org.flowerplatform.editor.remote.ContentTypeDescriptor; import org.flowerplatform.editor.remote.EditableResource; import org.flowerplatform.editor.remote.EditableResourceClient; import org.flowerplatform.editor.remote.EditorStatefulService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Cristian Spiescu */ public class EditorPlugin extends AbstractFlowerJavaPlugin { private static final Logger logger = LoggerFactory.getLogger(EditorPlugin.class); protected static EditorPlugin INSTANCE; public static EditorPlugin getInstance() { return INSTANCE; } public static final String TREE_NODE_KEY_CONTENT_TYPE = "contentType"; private Map<String, ContentTypeDescriptor> contentTypeDescriptorsMap; private List<ContentTypeDescriptor> contentTypeDescriptorsList; private Map<String, String> fileExtensionToContentTypeMap; private List<EditorStatefulService> editorStatefulServices = new ArrayList<EditorStatefulService>(); private IFileAccessController fileAccessController; /** * @author Cristian Spiescu * @author Cristina Constantinescu */ public void start(BundleContext bundleContext) throws Exception { super.start(bundleContext); INSTANCE = this; // content types contentTypeDescriptorsMap = new HashMap<String, ContentTypeDescriptor>(); contentTypeDescriptorsList = new ArrayList<ContentTypeDescriptor>(); int i = 0; IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.flowerplatform.editor.contentType"); for (IConfigurationElement configurationElement : configurationElements) { ContentTypeDescriptor descriptor = new ContentTypeDescriptor(); descriptor.setContentType(configurationElement.getAttribute("contentType")); descriptor.setIndex(i++); if (contentTypeDescriptorsMap.put(descriptor.getContentType(), descriptor) != null) { throw new IllegalArgumentException("Content type " + descriptor.getContentType() + " is registered by more that one extension!"); } contentTypeDescriptorsList.add(descriptor); } List<Editor> editors = new ArrayList<Editor>(); // content types to editor mappings configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.flowerplatform.editor.contentTypeToEditorMapping"); for (IConfigurationElement configurationElement : configurationElements) { String contentType = configurationElement.getAttribute("contentType"); String compatibleEditor = configurationElement.getAttribute("compatibleEditor"); String serviceId = configurationElement.getAttribute("serviceId"); boolean isDefaultEditor = Boolean.parseBoolean(configurationElement.getAttribute("isDefaultEditor")); int priorityEditor; if (configurationElement.getAttribute("priority") != null) { priorityEditor = Integer.parseInt(configurationElement.getAttribute("priority")); } else { // no priority, consider it the latest priorityEditor = Integer.MAX_VALUE; } editors.add(new Editor(compatibleEditor, contentType, isDefaultEditor, priorityEditor)); EditorStatefulService editorStatefulService = (EditorStatefulService) configurationElement.createExecutableExtension("editorStatefulService"); editorStatefulService.setEditorName(compatibleEditor); CommunicationPlugin.getInstance().getServiceRegistry().registerService(serviceId, editorStatefulService); editorStatefulServices.add(editorStatefulService); } // sort editors based on priority (smallest priority -> editor is shown first in Open With menu) Collections.sort(editors, new Comparator<Editor>() { @Override public int compare(Editor editor1, Editor editor2) { return Integer.compare(editor1.priority, editor2.priority); } }); for (Editor editor : editors) { if (editor.isDefault) { // default editors are added to all registered content types for (String contentType : contentTypeDescriptorsMap.keySet()) { addEditorToContentTypeDescriptor(editor.name, contentType); } } else { addEditorToContentTypeDescriptor(editor.name, editor.contentType); } } // file extensions to content types mappings fileExtensionToContentTypeMap = new HashMap<String, String>(); configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.flowerplatform.editor.fileExtensionToContentTypeMapping"); for (IConfigurationElement configurationElement : configurationElements) { String contentType = configurationElement.getAttribute("contentType"); String fileExtension = configurationElement.getAttribute("fileExtension"); ContentTypeDescriptor descriptor = contentTypeDescriptorsMap.get(contentType); if (descriptor == null) { throw new IllegalArgumentException("Cannot find contentType = " + contentType + " to associate with file extension = " + fileExtension); } if (fileExtensionToContentTypeMap.put(fileExtension, contentType) != null) { throw new IllegalArgumentException("Somebody already registered a content type for extension = " + fileExtension); } } if (logger.isDebugEnabled()) { logger.debug("Content types and compatible editors: {}", contentTypeDescriptorsList); logger.debug("File extensions to content types mappings: {}", fileExtensionToContentTypeMap); } // some custom serialzation descriptors new CustomSerializationDescriptor(EditableResource.class) .addDeclaredProperty("dirty") .addDeclaredProperty("lockOwner") .addDeclaredProperty("editorInput") .addDeclaredProperty("label") .addDeclaredProperty("lockUpdateTime") .addDeclaredProperty("masterEditorStatefulClientId") .addDeclaredProperty("iconUrl") .addDeclaredProperty("locked") .addDeclaredProperty("lockExpireTime") .addDeclaredProperty("editorStatefulClientId") .register(); new CustomSerializationDescriptor(EditableResourceClient.class) .addDeclaredProperty("name") .addDeclaredProperty("login") .addDeclaredProperty("communicationChannelId") .register(); } public void stop(BundleContext bundleContext) throws Exception { super.stop(bundleContext); INSTANCE = null; } public Map<String, ContentTypeDescriptor> getContentTypeDescriptorsMap() { return contentTypeDescriptorsMap; } public List<ContentTypeDescriptor> getContentTypeDescriptorsList() { return contentTypeDescriptorsList; } public Map<String, String> getFileExtensionToContentTypeMap() { return fileExtensionToContentTypeMap; } public List<EditorStatefulService> getEditorStatefulServices() { return editorStatefulServices; } public IFileAccessController getFileAccessController() { return fileAccessController; } public void setFileAccessController(IFileAccessController fileAccessController) { this.fileAccessController = fileAccessController; } public EditorStatefulService getEditorStatefulServiceByEditorName(String editorName) { for (EditorStatefulService editorStatefulService : editorStatefulServices) if (editorStatefulService.getEditorName().equals(editorName)) return editorStatefulService; return null; } /** * @author Cristian Spiescu * @author Cristina Constantinescu */ public String getContentTypeFromFileName(String fileName) { String contentType = null; int lastDotIndex = fileName.lastIndexOf('.'); if (lastDotIndex >= 0) { // has an extension String extension = fileName.substring(lastDotIndex + 1); contentType = EditorPlugin.getInstance().getFileExtensionToContentTypeMap().get(extension); if (contentType == null) { // not registered as extension, search it using * contentType = EditorPlugin.getInstance().getFileExtensionToContentTypeMap().get("*"); } } return contentType; } /** * @author Cristina Constantinescu */ private void addEditorToContentTypeDescriptor(String editorName, String contentType) { ContentTypeDescriptor descriptor = contentTypeDescriptorsMap.get(contentType); if (descriptor == null) { throw new IllegalArgumentException("Cannot find contentType = " + contentType + " to register the compatible editor = " + editorName); } descriptor.getCompatibleEditors().add(editorName); } public String getFriendlyNameDecoded(String friendlyName) { try { friendlyName = URLDecoder.decode(friendlyName, "UTF-8"); } catch (UnsupportedEncodingException e) { logger.error("Could not decode using UTF-8 charset : " + friendlyName); } return friendlyName; } private class Editor { public String name; public String contentType; public boolean isDefault; public int priority; public Editor(String name, String contentType, boolean isDefault, int priority) { this.name = name; this.contentType = contentType; this.isDefault = isDefault; this.priority = priority; } } }