/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.core.internal.command;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IRegistryEventListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.xmind.core.command.ICommand;
import org.xmind.core.command.ICommandHandler;
public class XMindCommandHandlerRegistry implements IRegistryEventListener {
private static final String EXT_POINT_ID = "handlers"; //$NON-NLS-1$
private static final String ATT_COMMAND = "command"; //$NON-NLS-1$
private static final String ATT_CLASS = "class"; //$NON-NLS-1$
private static final String ATT_ID = "id"; //$NON-NLS-1$
public static class CommandHandlerDescriptor {
private String id;
private Pattern pattern;
private IConfigurationElement element;
private ICommandHandler handler;
public CommandHandlerDescriptor(String id, IConfigurationElement element) {
String namePattern = element.getAttribute(ATT_COMMAND);
if (namePattern == null)
namePattern = ""; //$NON-NLS-1$
this.id = id;
this.pattern = Pattern.compile(namePattern);
this.element = element;
this.handler = null;
}
public String getId() {
return id;
}
public Matcher match(String commandName) {
return pattern.matcher(commandName);
}
public ICommandHandler getHandler() {
if (handler == null) {
try {
handler = (ICommandHandler) element
.createExecutableExtension(ATT_CLASS);
} catch (CoreException e) {
Logger.log(null, e);
}
}
return handler;
}
@Override
public String toString() {
return "CommandHandler{" + getId() + "}"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
private static final XMindCommandHandlerRegistry instance = new XMindCommandHandlerRegistry();
private List<CommandHandlerDescriptor> descriptors = null;
private Map<String, List<CommandHandlerDescriptor>> cache = null;
private XMindCommandHandlerRegistry() {
}
private synchronized List<CommandHandlerDescriptor> getHandlers() {
ensureLoaded();
return descriptors;
}
private void ensureLoaded() {
if (descriptors != null)
return;
loadFromExtensions();
if (descriptors == null)
descriptors = Collections.emptyList();
}
private void loadFromExtensions() {
IExtensionPoint point = Platform.getExtensionRegistry()
.getExtensionPoint(XMindCommandPlugin.PLUGIN_ID, EXT_POINT_ID);
if (point == null)
return;
IExtension[] extensions = point.getExtensions();
loadFromExtensions(extensions);
}
private void loadFromExtensions(IExtension[] extensions) {
for (int i = 0; i < extensions.length; i++) {
loadFromConfigurationElements(extensions[i]
.getConfigurationElements());
}
}
private void loadFromConfigurationElements(IConfigurationElement[] elements) {
for (int i = 0; i < elements.length; i++) {
loadFromConfigurationElement(elements[i]);
}
}
private void loadFromConfigurationElement(IConfigurationElement element) {
String name = element.getName();
if ("handler".equals(name)) { //$NON-NLS-1$
loadFromHandlerConfigurationElement(element);
loadFromConfigurationElements(element.getChildren());
}
}
private void loadFromHandlerConfigurationElement(
IConfigurationElement element) {
String id = element.getAttribute(ATT_ID);
if (id == null) {
Logger.log(new Status(IStatus.ERROR, element
.getNamespaceIdentifier(),
"Invalid extension: (id missing)")); //$NON-NLS-1$
return;
}
if (element.getAttribute(ATT_CLASS) == null) {
Logger.log(new Status(IStatus.ERROR, element
.getNamespaceIdentifier(),
"Invalid extension: (class missing)")); //$NON-NLS-1$
return;
}
registerContribution(new CommandHandlerDescriptor(id, element));
}
private void registerContribution(CommandHandlerDescriptor contribution) {
if (descriptors == null)
descriptors = new ArrayList<CommandHandlerDescriptor>();
descriptors.add(contribution);
}
synchronized List<CommandHandlerDescriptor> findMatchedHandlerDescriptors(
ICommand command) {
if (cache == null) {
cache = new HashMap<String, List<CommandHandlerDescriptor>>();
}
List<CommandHandlerDescriptor> list = cache.get(command
.getCommandName());
if (list == null) {
list = collectHandlers(command.getCommandName());
cache.put(command.getCommandName(), list);
}
return list;
}
private List<CommandHandlerDescriptor> collectHandlers(String commandName) {
List<CommandHandlerDescriptor> list = new ArrayList<CommandHandlerDescriptor>();
for (CommandHandlerDescriptor desc : getHandlers()) {
if (desc.match(commandName).matches()) {
list.add((CommandHandlerDescriptor) desc);
}
}
return list;
}
private void invalidate() {
descriptors = null;
cache = null;
}
public void added(IExtension[] extensions) {
invalidate();
}
public void removed(IExtension[] extensions) {
invalidate();
}
public void added(IExtensionPoint[] extensionPoints) {
// do nothing
}
public void removed(IExtensionPoint[] extensionPoints) {
// do nothing
}
public void installRegistryEventListener(IExtensionRegistry registry) {
if (registry == null)
return;
registry.addListener(this, XMindCommandPlugin.PLUGIN_ID + "." //$NON-NLS-1$
+ EXT_POINT_ID);
}
public void uninstallRegistryEventListener(IExtensionRegistry registry) {
if (registry == null)
return;
registry.removeListener(this);
}
public static XMindCommandHandlerRegistry getInstance() {
return instance;
}
}