/*******************************************************************************
* Copyright (c) 2005, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* 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.osgi.framework.Bundle;
/**
* Implementation of ObjectClassDefinition
*/
public class ObjectClassDefinitionImpl extends LocalizationElement implements EquinoxObjectClassDefinition, Cloneable {
private static final Comparator<Icon> iconComparator = new Comparator<Icon>() {
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 Vector<AttributeDefinitionImpl> _required = new Vector<AttributeDefinitionImpl>(7);
private final Vector<AttributeDefinitionImpl> _optional = new Vector<AttributeDefinitionImpl>(7);
private final ExtendableHelper helper;
// @GuardedBy("this")
private List<Icon> icons;
/*
* 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;
}
/*
*
*/
public synchronized Object clone() {
ObjectClassDefinitionImpl ocd = new ObjectClassDefinitionImpl(_name, _description, _id, _type, getLocalization(), helper);
for (int i = 0; i < _required.size(); i++) {
AttributeDefinitionImpl ad = _required.elementAt(i);
ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), true);
}
for (int i = 0; i < _optional.size(); i++) {
AttributeDefinitionImpl ad = _optional.elementAt(i);
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)
*/
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()];
Enumeration<AttributeDefinitionImpl> e = _required.elements();
int i = 0;
while (e.hasMoreElements()) {
atts[i] = e.nextElement();
i++;
}
e = _optional.elements();
while (e.hasMoreElements()) {
atts[i] = e.nextElement();
i++;
}
return atts;
}
}
/*
* Method to add one new AD to ObjectClassDefinition.
*/
void addAttributeDefinition(AttributeDefinitionImpl ad, boolean isRequired) {
if (isRequired) {
_required.addElement(ad);
} else {
_optional.addElement(ad);
}
}
/*
* (non-Javadoc)
*
* @see org.osgi.service.metatype.ObjectClassDefinition#getIcon(int)
*/
public synchronized 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;
}
synchronized 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);
Enumeration<AttributeDefinitionImpl> allADReqs = _required.elements();
while (allADReqs.hasMoreElements()) {
AttributeDefinitionImpl ad = allADReqs.nextElement();
ad.setLocaleAndBundle(assignedLocale, bundle);
}
Enumeration<AttributeDefinitionImpl> allADOpts = _optional.elements();
while (allADOpts.hasMoreElements()) {
AttributeDefinitionImpl ad = allADOpts.nextElement();
ad.setLocaleAndBundle(assignedLocale, bundle);
}
}
public Map<String, String> getExtensionAttributes(String schema) {
return helper.getExtensionAttributes(schema);
}
public Set<String> getExtensionUris() {
return helper.getExtensionUris();
}
}