Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.directory.studio.valueeditors; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.directory.api.ldap.model.schema.AttributeType; import org.apache.directory.api.ldap.model.schema.LdapSyntax; import org.apache.directory.api.util.Strings; import org.apache.directory.studio.ldapbrowser.common.BrowserCommonActivator; import org.apache.directory.studio.ldapbrowser.common.BrowserCommonConstants; import org.apache.directory.studio.ldapbrowser.core.model.AttributeHierarchy; import org.apache.directory.studio.ldapbrowser.core.model.IAttribute; import org.apache.directory.studio.ldapbrowser.core.model.IEntry; import org.apache.directory.studio.ldapbrowser.core.model.IValue; import org.apache.directory.studio.ldapbrowser.core.model.schema.Schema; import org.apache.directory.studio.ldapbrowser.core.model.schema.SchemaUtils; 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.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.plugin.AbstractUIPlugin; /** * A ValueEditorManager is used to manage value editors. It provides methods to get * the best or alternative value editors for a given attribute or value. It takes * user preferences into account when determine the best value editor. At least * it provides default text and binary value editors. * * The available value editors are specified by the extension point * <code>org.apache.directory.studio.valueeditors</code>. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public class ValueEditorManager { private static final String ATTRIBUTE_TYPE = "attributeType"; //$NON-NLS-1$ private static final String ATTRIBUTE = "attribute"; //$NON-NLS-1$ private static final String SYNTAX_OID = "syntaxOID"; //$NON-NLS-1$ private static final String SYNTAX = "syntax"; //$NON-NLS-1$ private static final String ICON = "icon"; //$NON-NLS-1$ private static final String NAME = "name"; //$NON-NLS-1$ private static final String CLASS = "class"; //$NON-NLS-1$ /** The extension point ID for value editors */ private static final String EXTENSION_POINT = BrowserCommonConstants.EXTENSION_POINT_VALUE_EDITORS; /** The composite used to create the value editors **/ private Composite parent; /** * The value editor explicitly selected by the user. If this * member is not null it is always returned as current value editor. */ private IValueEditor userSelectedValueEditor; /** The special value editor for multi-valued attributes */ private MultivaluedValueEditor multiValuedValueEditor; /** The special value editor to edit the entry in an wizard */ private EntryValueEditor entryValueEditor; /** The special value editor to rename the entry */ private RenameValueEditor renameValueEditor; /** The default string editor for single-line values */ private IValueEditor defaultStringSingleLineValueEditor; /** The default string editor for multi-line values */ private IValueEditor defaultStringMultiLineValueEditor; /** The default binary editor */ private IValueEditor defaultBinaryValueEditor; /** A map containing all available value editors. */ private Map<String, IValueEditor> class2ValueEditors; /** * Creates a new instance of ValueEditorManager. * * @param parent the composite used to create the value editors */ public ValueEditorManager(Composite parent, boolean useEntryValueEditor, boolean useRenameValueEditor) { this.parent = parent; userSelectedValueEditor = null; // init value editor map class2ValueEditors = new HashMap<String, IValueEditor>(); Collection<IValueEditor> valueEditors = createValueEditors(parent); for (IValueEditor valueEditor : valueEditors) { class2ValueEditors.put(valueEditor.getClass().getName(), valueEditor); } // special case: multivalued editor multiValuedValueEditor = new MultivaluedValueEditor(this.parent, this); multiValuedValueEditor.setValueEditorName(Messages.getString("ValueEditorManager.MulitivaluedEditor")); //$NON-NLS-1$ multiValuedValueEditor.setValueEditorImageDescriptor(BrowserCommonActivator.getDefault() .getImageDescriptor(BrowserCommonConstants.IMG_MULTIVALUEDEDITOR)); // special case: entry editor if (useEntryValueEditor) { entryValueEditor = new EntryValueEditor(this.parent, this); entryValueEditor.setValueEditorName(Messages.getString("ValueEditorManager.EntryEditor")); //$NON-NLS-1$ entryValueEditor.setValueEditorImageDescriptor(BrowserCommonActivator.getDefault() .getImageDescriptor(BrowserCommonConstants.IMG_ENTRY_EDITOR)); } // special case: rename editor if (useRenameValueEditor) { renameValueEditor = new RenameValueEditor(this.parent, this); renameValueEditor.setValueEditorName(Messages.getString("ValueEditorManager.RenameEditor")); //$NON-NLS-1$ renameValueEditor.setValueEditorImageDescriptor( BrowserCommonActivator.getDefault().getImageDescriptor(BrowserCommonConstants.IMG_RENAME)); } // get default editors from value editor map defaultStringSingleLineValueEditor = class2ValueEditors.get(InPlaceTextValueEditor.class.getName()); defaultStringMultiLineValueEditor = class2ValueEditors.get(TextValueEditor.class.getName()); defaultBinaryValueEditor = class2ValueEditors.get(HexValueEditor.class.getName()); } /** * Disposes all value editors. */ public void dispose() { if (parent != null) { userSelectedValueEditor = null; multiValuedValueEditor.dispose(); if (entryValueEditor != null) { entryValueEditor.dispose(); } if (renameValueEditor != null) { renameValueEditor.dispose(); } defaultStringSingleLineValueEditor.dispose(); defaultStringMultiLineValueEditor.dispose(); defaultBinaryValueEditor.dispose(); for (IValueEditor ve : class2ValueEditors.values()) { ve.dispose(); } parent = null; } } /** * Sets the value editor explicitly selected by the user. Set * userSelectedValueEditor to null to remove the selection. * * @param userSelectedValueEditor the user selected value editor, may be null. */ public void setUserSelectedValueEditor(IValueEditor userSelectedValueEditor) { this.userSelectedValueEditor = userSelectedValueEditor; } /** * Gets the value editor explicitly selected by the user. * * @return the user selected value editor, null if non is set */ public IValueEditor getUserSelectedValueEditor() { return userSelectedValueEditor; } /** * Returns the current (best) value editor for the given attribute. * * <ol> * <li>If a user selected value editor is selected, this is returned. * <li>If a specific value editor is defined for the attribute type this * value editor is returned. See preferences. * <li>If a specific value editor is defined for the attribute's syntax this * value editor is returned. See preferences. * <li>Otherwise a default value editor is returned. If the attribute is * binary the default Hex Editor is returned. Otherwise the default * Text Editor is returned. * </ol> * * @param schema the schema * @param attributeType the attribute type * @return the current value editor */ public IValueEditor getCurrentValueEditor(Schema schema, String attributeType) { // check user-selected (forced) value editor if (userSelectedValueEditor != null) { return userSelectedValueEditor; } AttributeType atd = schema.getAttributeTypeDescription(attributeType); // check attribute preferences Map<String, String> attributeValueEditorMap = BrowserCommonActivator.getDefault() .getValueEditorsPreferences().getAttributeValueEditorMap(); String oidStr = Strings.toLowerCase(atd.getOid()); if (atd.getOid() != null && attributeValueEditorMap.containsKey(oidStr)) { return (IValueEditor) class2ValueEditors.get(attributeValueEditorMap.get(oidStr)); } List<String> names = atd.getNames(); for (String name : names) { String nameStr = Strings.toLowerCase(name); if (attributeValueEditorMap.containsKey(nameStr)) { return (IValueEditor) class2ValueEditors.get(attributeValueEditorMap.get(nameStr)); } } // check syntax preferences String syntaxNumericOid = SchemaUtils.getSyntaxNumericOidTransitive(atd, schema); Map<String, String> syntaxValueEditorMap = BrowserCommonActivator.getDefault().getValueEditorsPreferences() .getSyntaxValueEditorMap(); String syntaxtNumericOidStr = Strings.toLowerCase(syntaxNumericOid); if ((syntaxNumericOid != null) && syntaxValueEditorMap.containsKey(syntaxtNumericOidStr)) { return (IValueEditor) class2ValueEditors.get(syntaxValueEditorMap.get(syntaxtNumericOidStr)); } // return default LdapSyntax lsd = schema.getLdapSyntaxDescription(syntaxNumericOid); if (SchemaUtils.isBinary(lsd)) { return defaultBinaryValueEditor; } else { return defaultStringSingleLineValueEditor; } } /** * Returns the current (best) value editor for the given attribute. * * @param entry the entry * @param attributeType the attributge type * @return the current value editor * @see #getCurrentValueEditor( Schema, String ) */ public IValueEditor getCurrentValueEditor(IEntry entry, String attributeType) { return getCurrentValueEditor(entry.getBrowserConnection().getSchema(), attributeType); } /** * Returns the current (best) value editor for the given value. * * @param value the value * @return the current value editor * @see #getCurrentValueEditor( Schema, String ) */ public IValueEditor getCurrentValueEditor(IValue value) { IAttribute attribute = value.getAttribute(); IValueEditor ve = getCurrentValueEditor(attribute.getEntry(), attribute.getDescription()); // special case objectClass: always return entry editor if (userSelectedValueEditor == null) { if (attribute.isObjectClassAttribute() && (entryValueEditor != null)) { return entryValueEditor; } // special case Rdn attribute: always return rename editor if (value.isRdnPart() && (renameValueEditor != null)) { return renameValueEditor; } } // here the value is known, we can check for single-line or multi-line if (ve == defaultStringSingleLineValueEditor) { String stringValue = value.getStringValue(); if ((stringValue.indexOf('\n') == -1) && (stringValue.indexOf('\r') == -1)) { ve = defaultStringSingleLineValueEditor; } else { ve = defaultStringMultiLineValueEditor; } } return ve; } /** * Returns the current (best) value editor for the given attribute. * * @param attributeHierarchy the attribute hierarchy * @return the current value editor * @see #getCurrentValueEditor( Schema, String ) */ public IValueEditor getCurrentValueEditor(AttributeHierarchy attributeHierarchy) { if (attributeHierarchy == null) { return null; } else if ((userSelectedValueEditor == null) && attributeHierarchy.getAttribute().isObjectClassAttribute() && entryValueEditor != null) { // special case objectClass: always return entry editor return entryValueEditor; } else if ((userSelectedValueEditor == entryValueEditor) && (entryValueEditor != null)) { // special case objectClass: always return entry editor return entryValueEditor; } else if ((attributeHierarchy.size() == 1) && (attributeHierarchy.getAttribute().getValueSize() == 0)) { return getCurrentValueEditor(attributeHierarchy.getAttribute().getEntry(), attributeHierarchy.getAttribute().getDescription()); } else if ((attributeHierarchy.size() == 1) && (attributeHierarchy.getAttribute().getValueSize() == 1) && attributeHierarchy.getAttributeDescription().equalsIgnoreCase( attributeHierarchy.getAttribute().getValues()[0].getAttribute().getDescription())) { // special case Rdn: always return MV-editor if ((userSelectedValueEditor == null) && attributeHierarchy.getAttribute().getValues()[0].isRdnPart()) { if (renameValueEditor != null) { return renameValueEditor; } else { return multiValuedValueEditor; } } return getCurrentValueEditor(attributeHierarchy.getAttribute().getValues()[0]); } else { return multiValuedValueEditor; } } /** * Returns alternative value editors for the given attribute. For now these * are the three default editors. * * @param entry the entry * @param attributeName the attribute * @return alternative value editors */ public IValueEditor[] getAlternativeValueEditors(IEntry entry, String attributeName) { Schema schema = entry.getBrowserConnection().getSchema(); return getAlternativeValueEditors(schema, attributeName); } /** * Returns alternative value editors for the given attribute. For now these * are the three default editors. * * @param schema the schema * @param attributeName the attribute * @return the alternative value editors */ public IValueEditor[] getAlternativeValueEditors(Schema schema, String attributeName) { List<IValueEditor> alternativeList = new ArrayList<IValueEditor>(); AttributeType atd = schema.getAttributeTypeDescription(attributeName); if (SchemaUtils.isBinary(atd, schema)) { alternativeList.add(defaultBinaryValueEditor); alternativeList.add(defaultStringSingleLineValueEditor); alternativeList.add(defaultStringMultiLineValueEditor); } else if (SchemaUtils.isString(atd, schema)) { alternativeList.add(defaultStringSingleLineValueEditor); alternativeList.add(defaultStringMultiLineValueEditor); alternativeList.add(defaultBinaryValueEditor); } alternativeList.add(multiValuedValueEditor); alternativeList.remove(getCurrentValueEditor(schema, attributeName)); return alternativeList.toArray(new IValueEditor[alternativeList.size()]); } /** * Returns alternative value editors for the given value. For now these * are the three default editors. * * @param value the value * @return the alternative value editors */ public IValueEditor[] getAlternativeValueEditors(IValue value) { List<IValueEditor> alternativeList = new ArrayList<IValueEditor>(); if (value.isBinary()) { alternativeList.add(defaultBinaryValueEditor); alternativeList.add(defaultStringSingleLineValueEditor); alternativeList.add(defaultStringMultiLineValueEditor); } else if (value.isString()) { alternativeList.add(defaultStringSingleLineValueEditor); alternativeList.add(defaultStringMultiLineValueEditor); alternativeList.add(defaultBinaryValueEditor); } alternativeList.add(multiValuedValueEditor); alternativeList.remove(getCurrentValueEditor(value)); return alternativeList.toArray(new IValueEditor[alternativeList.size()]); } /** * Returns alternative value editors for the given value. For now these * are the three default editors. * * @param ah the attribute hierarchy * @return alternative value editors */ public IValueEditor[] getAlternativeValueEditors(AttributeHierarchy ah) { if (ah == null) { return new IValueEditor[0]; } // special case Rdn: no alternative to the rename editor, except the MV editor // perhaps this should be moved somewhere else if (multiValuedValueEditor != null) { for (IAttribute attribute : ah) { for (IValue value : attribute.getValues()) { if (value.isRdnPart()) { return new IValueEditor[] { multiValuedValueEditor }; } } } } // special case objectClass: no alternative to the entry editor // perhaps this should be moved somewhere else for (IAttribute attribute : ah) { if (attribute.isObjectClassAttribute()) { return new IValueEditor[0]; } } if ((ah.size() == 1) && (ah.getAttribute().getValueSize() == 0)) { return getAlternativeValueEditors(ah.getAttribute().getEntry(), ah.getAttribute().getDescription()); } else if ((ah.size() == 1) && (ah.getAttribute().getValueSize() == 1) && ah.getAttributeDescription() .equalsIgnoreCase(ah.getAttribute().getValues()[0].getAttribute().getDescription())) { return getAlternativeValueEditors(ah.getAttribute().getValues()[0]); } else { return new IValueEditor[0]; } } /** * Returns all available value editors. * * @return all available value editors */ public IValueEditor[] getAllValueEditors() { // use a set to avoid double entries Set<IValueEditor> list = new LinkedHashSet<IValueEditor>(); list.add(defaultStringSingleLineValueEditor); list.add(defaultStringMultiLineValueEditor); list.add(defaultBinaryValueEditor); list.addAll(class2ValueEditors.values()); list.add(multiValuedValueEditor); if (entryValueEditor != null) { list.add(entryValueEditor); } if (renameValueEditor != null) { list.add(renameValueEditor); } return list.toArray(new IValueEditor[list.size()]); } /** * Returns the default binary editor (a HexEditor). * * @return the default binary editor */ public IValueEditor getDefaultBinaryValueEditor() { return defaultBinaryValueEditor; } /** * Returns the default string editor (a TextEditor). * * @return the default string editor */ public IValueEditor getDefaultStringValueEditor() { return defaultStringMultiLineValueEditor; } /** * Returns the multi-valued editor. * * @return the multi-valued editor */ public MultivaluedValueEditor getMultiValuedValueEditor() { return multiValuedValueEditor; } /** * Returns the entry value editor. * * @return the entry value editor */ public EntryValueEditor getEntryValueEditor() { return entryValueEditor; } /** * Returns the rename value editor. * * @return the rename value editor */ public RenameValueEditor getRenameValueEditor() { return renameValueEditor; } /** * Creates and returns the value editors specified by value editors extensions. * * @param parent the parent composite * @return the value editors */ private Collection<IValueEditor> createValueEditors(Composite parent) { Collection<IValueEditor> valueEditors = new ArrayList<IValueEditor>(); Collection<ValueEditorExtension> valueEditorExtensions = getValueEditorExtensions(); for (ValueEditorExtension vee : valueEditorExtensions) { try { IValueEditor valueEditor = (IValueEditor) vee.member.createExecutableExtension(CLASS); valueEditor.create(parent); valueEditor.setValueEditorName(vee.name); valueEditor.setValueEditorImageDescriptor(vee.icon); valueEditors.add(valueEditor); } catch (Exception e) { BrowserCommonActivator.getDefault().getLog() .log(new Status(IStatus.ERROR, BrowserCommonConstants.PLUGIN_ID, 1, Messages.getString("ValueEditorManager.UnableToCreateValueEditor") //$NON-NLS-1$ + vee.className, e)); } } return valueEditors; } /** * Returns all value editor extensions specified by value editor extensions. * * @return the value editor extensions */ public static Collection<ValueEditorExtension> getValueEditorExtensions() { Collection<ValueEditorExtension> valueEditorExtensions = new ArrayList<ValueEditorExtension>(); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry.getExtensionPoint(EXTENSION_POINT); IConfigurationElement[] members = extensionPoint.getConfigurationElements(); // For each extension: for (IConfigurationElement member : members) { ValueEditorExtension proxy = new ValueEditorExtension(); valueEditorExtensions.add(proxy); IExtension extension = member.getDeclaringExtension(); String extendingPluginId = extension.getNamespaceIdentifier(); proxy.member = member; proxy.name = member.getAttribute(NAME); String iconPath = member.getAttribute(ICON); proxy.icon = AbstractUIPlugin.imageDescriptorFromPlugin(extendingPluginId, iconPath); if (proxy.icon == null) { proxy.icon = ImageDescriptor.getMissingImageDescriptor(); } proxy.className = member.getAttribute(CLASS); IConfigurationElement[] children = member.getChildren(); for (IConfigurationElement child : children) { String type = child.getName(); if (SYNTAX.equals(type)) { String syntaxOID = child.getAttribute(SYNTAX_OID); proxy.syntaxOids.add(syntaxOID); } else if (ATTRIBUTE.equals(type)) { String attributeType = child.getAttribute(ATTRIBUTE_TYPE); proxy.attributeTypes.add(attributeType); } } } return valueEditorExtensions; } /** * This class is a bean to hold the data defined in value editor extension * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public static class ValueEditorExtension { /** The name. */ public String name = null; /** The icon. */ public ImageDescriptor icon = null; /** The class name. */ public String className = null; /** The syntax oids. */ public Collection<String> syntaxOids = new ArrayList<String>(3); /** The attribute types. */ public Collection<String> attributeTypes = new ArrayList<String>(3); /** The configuration element. */ private IConfigurationElement member = null; /** * @see Object#toString() */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append('<'); sb.append(name).append(", "); sb.append(className); if ((attributeTypes != null) && (attributeTypes.size() > 0)) { sb.append(", {"); boolean isFirst = true; for (String attributeType : attributeTypes) { if (isFirst) { isFirst = false; } else { sb.append(", "); } sb.append(attributeType); } sb.append('}'); } if ((syntaxOids != null) && (syntaxOids.size() > 0)) { sb.append(", {"); boolean isFirst = true; for (String syntaxOid : syntaxOids) { if (isFirst) { isFirst = false; } else { sb.append(", "); } sb.append(syntaxOid); } sb.append('}'); } sb.append('>'); return sb.toString(); } } }