| /******************************************************************************* |
| * Copyright (c) 2005, 2011 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.equinox.metatype.impl; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.util.*; |
| import org.eclipse.equinox.metatype.EquinoxAttributeDefinition; |
| import org.eclipse.equinox.metatype.EquinoxObjectClassDefinition; |
| import org.eclipse.equinox.metatype.impl.Persistence.Writer; |
| import org.osgi.framework.Bundle; |
| |
| /** |
| * Implementation of ObjectClassDefinition |
| */ |
| public class ObjectClassDefinitionImpl extends LocalizationElement implements EquinoxObjectClassDefinition, Cloneable { |
| private static final Comparator<Icon> iconComparator = new Comparator<Icon>() { |
| @Override |
| public int compare(Icon icon1, Icon icon2) { |
| return icon1.getIconSize().compareTo(icon2.getIconSize()); |
| } |
| }; |
| |
| private final String _name; |
| private final String _id; |
| private final String _description; |
| private final int _type; |
| private final List<AttributeDefinitionImpl> _required = new ArrayList<>(7); |
| private final List<AttributeDefinitionImpl> _optional = new ArrayList<>(7); |
| private final ExtendableHelper helper; |
| |
| private volatile List<Icon> icons = null; |
| |
| /* |
| * Constructor of class ObjectClassDefinitionImpl. |
| */ |
| public ObjectClassDefinitionImpl(String name, String description, String id, String localization, Map<String, Map<String, String>> extensionAttributes) { |
| this(name, description, id, 0, localization, new ExtendableHelper(extensionAttributes)); |
| } |
| |
| /* |
| * Constructor of class ObjectClassDefinitionImpl. |
| */ |
| public ObjectClassDefinitionImpl(String name, String description, String id, int type, String localization, ExtendableHelper helper) { |
| super(localization); |
| this._name = name; |
| this._id = id; |
| this._description = description; |
| this._type = type; |
| this.helper = helper; |
| } |
| |
| /* |
| * |
| */ |
| @Override |
| public Object clone() { |
| |
| ObjectClassDefinitionImpl ocd = new ObjectClassDefinitionImpl(_name, _description, _id, _type, getLocalization(), helper); |
| for (AttributeDefinitionImpl ad : _required) { |
| ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), true); |
| } |
| for (AttributeDefinitionImpl ad : _optional) { |
| ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), false); |
| } |
| if (icons != null) { |
| ocd.setIcons(new ArrayList<Icon>(icons)); |
| } |
| return ocd; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.osgi.service.metatype.ObjectClassDefinition#getName() |
| */ |
| public String getName() { |
| return getLocalized(_name); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.osgi.service.metatype.ObjectClassDefinition#getID() |
| */ |
| public String getID() { |
| return _id; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.osgi.service.metatype.ObjectClassDefinition#getDescription() |
| */ |
| public String getDescription() { |
| return getLocalized(_description); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.osgi.service.metatype.ObjectClassDefinition#getAttributeDefinitions(int) |
| */ |
| @Override |
| public EquinoxAttributeDefinition[] getAttributeDefinitions(int filter) { |
| |
| EquinoxAttributeDefinition[] atts; |
| switch (filter) { |
| case REQUIRED : |
| atts = new EquinoxAttributeDefinition[_required.size()]; |
| _required.toArray(atts); |
| return atts; |
| case OPTIONAL : |
| atts = new EquinoxAttributeDefinition[_optional.size()]; |
| _optional.toArray(atts); |
| return atts; |
| case ALL : |
| default : |
| atts = new EquinoxAttributeDefinition[_required.size() + _optional.size()]; |
| int i = 0; |
| for (AttributeDefinitionImpl attr : _required) { |
| atts[i] = attr; |
| i++; |
| } |
| for (AttributeDefinitionImpl attr : _optional) { |
| atts[i] = attr; |
| i++; |
| } |
| return atts; |
| } |
| } |
| |
| /* |
| * Method to add one new AD to ObjectClassDefinition. |
| */ |
| void addAttributeDefinition(AttributeDefinitionImpl ad, boolean isRequired) { |
| |
| if (isRequired) { |
| _required.add(ad); |
| } else { |
| _optional.add(ad); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.osgi.service.metatype.ObjectClassDefinition#getIcon(int) |
| */ |
| public InputStream getIcon(int sizeHint) throws IOException { |
| // The parameter simply represents a requested size. This method should never return null if an |
| // icon exists. |
| // Temporary icon to hold the requested size for use in binary search comparator. |
| Icon icon = new Icon(null, sizeHint, null); |
| @SuppressWarnings("hiding") |
| // Use a local reference to the icon list to be sure we don't suddenly start using a new one. |
| List<Icon> icons = this.icons; |
| // Icons will be null if none were specified. |
| if (icons == null) |
| return null; |
| int index = Collections.binarySearch(icons, icon, iconComparator); |
| if (index < 0) { |
| // If the index is less than zero, there wasn't an exact match. |
| // Compute the insertion point. This will be the index of the first icon whose |
| // size was greater than the requested size, or the list's length if there were none. |
| int insertionPoint = -(index + 1); |
| Icon lessThan = insertionPoint == 0 ? null : icons.get(insertionPoint - 1); |
| Icon greaterThan = insertionPoint == icons.size() ? null : icons.get(insertionPoint); |
| if (lessThan == null) |
| // There were no icons whose size was smaller than the requested size. |
| icon = greaterThan; |
| else if (greaterThan == null) |
| // There were no icons whose size was greater than the requested size. |
| icon = lessThan; |
| else { |
| // There was at least one icon with a smaller size and at least one with |
| // a greater size than the requested size. Compute the average to see which one to choose. |
| int average = (greaterThan.getIconSize() + lessThan.getIconSize()) / 2; |
| if (sizeHint < average) |
| // The smaller icon is closer to the requested size. |
| icon = lessThan; |
| else |
| // The larger icon is closer to the requested size. |
| icon = greaterThan; |
| } |
| } else |
| // The index was greater than or equal to zero, indicating the index of an exact match. |
| icon = icons.get(index); |
| Bundle b = icon.getIconBundle(); |
| URL[] urls = FragmentUtils.findEntries(b, getLocalized(icon.getIconName())); |
| if (urls != null && urls.length > 0) { |
| return urls[0].openStream(); |
| } |
| return null; |
| } |
| |
| void setIcons(List<Icon> icons) { |
| // Do nothing if icons is null or empty. |
| if (icons == null || icons.isEmpty()) |
| return; |
| // Prepare the list of icons for binary searches as in getIcon(int). |
| Collections.sort(icons, iconComparator); |
| // Make the list unmodifiable for safe binary searches without copying. |
| // We assume the caller makes no modifications to the list. |
| this.icons = Collections.unmodifiableList(icons); |
| } |
| |
| /** |
| * Method to set the resource bundle for this OCD and all its ADs. |
| */ |
| void setResourceBundle(String assignedLocale, Bundle bundle) { |
| setLocaleAndBundle(assignedLocale, bundle); |
| for (AttributeDefinitionImpl ad : _required) { |
| ad.setLocaleAndBundle(assignedLocale, bundle); |
| } |
| for (AttributeDefinitionImpl ad : _optional) { |
| ad.setLocaleAndBundle(assignedLocale, bundle); |
| } |
| } |
| |
| @Override |
| public Map<String, String> getExtensionAttributes(String schema) { |
| return helper.getExtensionAttributes(schema); |
| } |
| |
| @Override |
| public Set<String> getExtensionUris() { |
| return helper.getExtensionUris(); |
| } |
| |
| void getStrings(Set<String> strings) { |
| helper.getStrings(strings); |
| strings.add(_description); |
| strings.add(_id); |
| strings.add(_name); |
| strings.add(getLocalization()); |
| @SuppressWarnings("hiding") |
| List<Icon> icons = this.icons; |
| if (icons != null) { |
| for (Icon icon : icons) { |
| icon.getStrings(strings); |
| } |
| } |
| } |
| |
| static ObjectClassDefinitionImpl load(Bundle b, LogTracker logger, Persistence.Reader reader) throws IOException { |
| String description = reader.readString(); |
| String id = reader.readString(); |
| String name = reader.readString(); |
| int type = reader.readInt(); |
| String localization = reader.readString(); |
| ExtendableHelper helper = ExtendableHelper.load(reader); |
| ObjectClassDefinitionImpl result = new ObjectClassDefinitionImpl(name, description, id, type, localization, helper); |
| |
| int numIcons = reader.readInt(); |
| List<Icon> icons = null; |
| if (numIcons > 0) { |
| icons = new ArrayList<>(numIcons); |
| for (int i = 0; i < numIcons; i++) { |
| icons.add(Icon.load(reader, b)); |
| } |
| } |
| result.setIcons(icons); |
| |
| int numRequired = reader.readInt(); |
| for (int i = 0; i < numRequired; i++) { |
| result.addAttributeDefinition(AttributeDefinitionImpl.load(reader, logger), true); |
| } |
| int numOptional = reader.readInt(); |
| for (int i = 0; i < numOptional; i++) { |
| result.addAttributeDefinition(AttributeDefinitionImpl.load(reader, logger), false); |
| } |
| |
| return result; |
| } |
| |
| void write(Writer writer) throws IOException { |
| writer.writeString(_description); |
| writer.writeString(_id); |
| writer.writeString(_name); |
| writer.writeInt(_type); |
| writer.writeString(getLocalization()); |
| helper.write(writer); |
| List<Icon> curIcons = this.icons; |
| writer.writeInt(curIcons == null ? 0 : curIcons.size()); |
| if (curIcons != null) { |
| for (Icon icon : curIcons) { |
| icon.write(writer); |
| } |
| } |
| writer.writeInt(_required.size()); |
| for (AttributeDefinitionImpl ad : _required) { |
| ad.write(writer); |
| } |
| writer.writeInt(_optional.size()); |
| for (AttributeDefinitionImpl ad : _optional) { |
| ad.write(writer); |
| } |
| } |
| } |