/* * Copyright (c) 2006, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @author Philippe Laporte */ //TODO lots of optimization to be done, both in speed and storage package org.knopflerfish.util.metatype; import java.io.*; import java.net.URL; import java.util.Hashtable; import java.util.Iterator; import java.util.Locale; import java.util.Properties; import java.util.Set; import java.util.Vector; import java.util.Enumeration; import java.util.Dictionary; import org.osgi.framework.*; import org.osgi.service.cm.Configuration; import org.osgi.service.metatype.MetaTypeInformation; import org.osgi.service.metatype.ObjectClassDefinition; import org.osgi.service.metatype.AttributeDefinition; import java.lang.reflect.*; //TODO lots of optimization public class BundleMetaTypeResource implements MetaTypeInformation{ private Bundle bundle; private Vector metaDatas = new Vector(); //id -> MetaData private Hashtable pids = new Hashtable(); private Hashtable factoryPids = new Hashtable(); private String[] locales; public BundleMetaTypeResource(Bundle bundle){ this.bundle = bundle; } public Bundle getBundle() { return bundle; } public void addMetaData(MetaData md){ metaDatas.add(md); } public String[] getFactoryPids() { Vector factoryPidsV = new Vector(); factoryPidsV.addAll(factoryPids.keySet()); return (String[]) factoryPidsV.toArray(new String[factoryPidsV.size()]); } public String[] getPids() { Vector pidsV = new Vector(); pidsV.addAll(pids.keySet()); return (String[]) pidsV.toArray(new String[pidsV.size()]); } public void prepare(){ Enumeration enume = metaDatas.elements(); while(enume.hasMoreElements()){ MetaData md = (MetaData) enume.nextElement(); Iterator it = md.getPids().iterator(); while(it.hasNext()){ pids.put((String) it.next(), md); } it = md.getFactoryPids().iterator(); while(it.hasNext()){ factoryPids.put((String) it.next(), md); } if(locales != null){ String[] newLocales = md.getLocales(); String[] temp = new String[locales.length + newLocales.length]; System.arraycopy(locales, 0, temp, 0, locales.length); System.arraycopy(newLocales, 0, temp, locales.length, newLocales.length); locales = temp; } else{ locales = md.getLocales(); } } } public String[] getLocales() { return locales; } public ObjectClassDefinition getObjectClassDefinition(String id, String locale) { MetaData md; md = (MetaData) pids.get(id); if(md == null){ md = (MetaData) factoryPids.get(id); } if(md == null){ throw new IllegalArgumentException("no information available for id " + id); } if(locale == null){ locale = Locale.getDefault().toString(); } //TODO validate locale return md.getOCD(id, locale); } void mergeWith(BundleMetaTypeResource other){ if(other == null){ return; } if(bundle != other.bundle){ return; } Enumeration enume = other.metaDatas.elements(); while(enume.hasMoreElements()){ metaDatas.add(enume.nextElement()); } } } //TODO localization specs not definite yet class MetaData { private String localizationFileBaseName; private Hashtable pids = new Hashtable(); private Hashtable factoryPids = new Hashtable(); private Hashtable OCDs = new Hashtable(); private String[] locales; private Bundle bundle; final static private String locBaseDir = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME.substring(0, 14); //TODO check for Attributes manifest's Constants.BUNDLE_LOCALIZATION public MetaData(String localizationFile, Bundle bundle){ this.localizationFileBaseName = localizationFile; this.bundle = bundle; } public MetaData(Bundle bundle){ this.localizationFileBaseName = "bundle"; this.bundle = bundle; } public void prepare(){ loadLocales(); } public String[] getLocales(){ return locales; } public Set getFactoryPids() { return factoryPids.keySet(); } public Set getPids() { return pids.keySet(); } public void addOCD(ObjectClassDefinition ocd){ OCDs.put(ocd.getID(), ocd); } //TODO locale finding rules not definite ObjectClassDefinition getOCD(String id, String locale){ OCD ocd = (OCD) pids.get(id); if(ocd == null){ ocd = (OCD) factoryPids.get(id); } if(ocd == null) return null; Enumeration url; int underscore; url = bundle.findEntries(locBaseDir, localizationFileBaseName + "_" + locale + ".properties", false); if(url == null){ underscore = locale.lastIndexOf('_'); if(underscore > 0){ locale = locale.substring(0, underscore - 1); } url = bundle.findEntries(locBaseDir, localizationFileBaseName + "_" + locale + ".properties", false); if(url == null){ underscore = locale.lastIndexOf('_'); if(underscore > 0){ locale = locale.substring(0, underscore - 1); } url = bundle.findEntries(locBaseDir, localizationFileBaseName + "_" + locale + ".properties", false); } locale = Locale.getDefault().toString(); url = bundle.findEntries(locBaseDir, localizationFileBaseName + "_" + locale + ".properties", false); if(url == null){ underscore = locale.lastIndexOf('_'); if(underscore > 0){ locale = locale.substring(0, underscore - 1); } url = bundle.findEntries(locBaseDir, localizationFileBaseName + "_" + locale + ".properties", false); if(url == null){ underscore = locale.lastIndexOf('_'); if(underscore > 0){ locale = locale.substring(0, underscore - 1); } url = bundle.findEntries(locBaseDir, localizationFileBaseName + "_" + locale + ".properties", false); } //lastly if(url == null){ url = bundle.findEntries(locBaseDir, localizationFileBaseName + ".properties", false); } } } if (url != null) { ocd.localize(loadLocaleEntries((URL)url.nextElement())); } return ocd; } public void designate(String factoryPid, String pid, String ocdref, Configuration conf, Vector currentAttributes){ ObjectClassDefinition ocd; ocd = (ObjectClassDefinition) OCDs.get(ocdref); if(ocd != null){ if(conf != null && currentAttributes.size() > 0){ AttributeDefinition[] attrDefs = ocd.getAttributeDefinitions(ObjectClassDefinition.ALL); Hashtable ADs = new Hashtable(); //id is key for(int i = 0; i < attrDefs.length; i++){ AttributeDefinition ad = attrDefs[i]; ADs.put(ad.getID(), ad); } Dictionary props = conf.getProperties(); Enumeration attrsAssigns = currentAttributes.elements(); while(attrsAssigns.hasMoreElements()){ AE ae = (AE) attrsAssigns.nextElement(); AttributeDefinition ad = (AttributeDefinition) ADs.get(ae.adref); if(ad != null){ Object value = null; int card = ad.getCardinality(); switch(ad.getType()){ case AttributeDefinition.STRING: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(values.nextElement()); } } else if(card > 0){ value = new String[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((String[])value)[i] = (String) values.nextElement(); } } else{ value = ae.values.elementAt(0); } break; case AttributeDefinition.BOOLEAN: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(Boolean.valueOf((String)values.nextElement())); } } else if(card > 0){ value = new Boolean[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Boolean[])value)[i] = Boolean.valueOf((String) values.nextElement()); } } else{ value = Boolean.valueOf((String) ae.values.elementAt(0)); } break; case AttributeDefinition.BYTE: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(Byte.valueOf((String)values.nextElement())); } } else if(card > 0){ value = new Byte[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Byte[])value)[i] = Byte.valueOf((String) values.nextElement()); } } else{ value = Byte.valueOf((String) ae.values.elementAt(0)); } break; case AttributeDefinition.DOUBLE: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(Double.valueOf((String)values.nextElement())); } } else if(card > 0){ value = new Double[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Double[])value)[i] = Double.valueOf((String) values.nextElement()); } } else{ value = Double.valueOf((String) ae.values.elementAt(0)); } break; case AttributeDefinition.FLOAT: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(Float.valueOf((String)values.nextElement())); } } else if(card > 0){ value = new Float[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Float[])value)[i] = Float.valueOf((String) values.nextElement()); } } else{ value = Float.valueOf((String) ae.values.elementAt(0)); } break; case AttributeDefinition.INTEGER: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(Integer.valueOf((String)values.nextElement())); } } else if(card > 0){ value = new Integer[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Integer[])value)[i] = Integer.valueOf((String) values.nextElement()); } } else{ value = Integer.valueOf((String) ae.values.elementAt(0)); } break; case AttributeDefinition.LONG: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(Long.valueOf((String)values.nextElement())); } } else if(card > 0){ value = new Long[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Long[])value)[i] = Long.valueOf((String) values.nextElement()); } } else{ value = Long.valueOf((String) ae.values.elementAt(0)); } break; case AttributeDefinition.SHORT: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(Short.valueOf((String)values.nextElement())); } } else if(card > 0){ value = new Integer[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Short[])value)[i] = Short.valueOf((String) values.nextElement()); } } else{ value = Short.valueOf((String) ae.values.elementAt(0)); } break; case AttributeDefinition.CHARACTER: if(card < 0){ value = new Vector(-1 * card); Enumeration values = ae.values.elements(); while(values.hasMoreElements()){ ((Vector)value).add(new Character(((String)values.nextElement()).charAt(0))); } } else if(card > 0){ value = new Character[card]; Enumeration values = ae.values.elements(); for(int i = 0; values.hasMoreElements(); i++){ ((Character[])value)[i] = new Character(((String)values.nextElement()).charAt(0)); } } else{ value = new Character(((String) ae.values.elementAt(0)).charAt(0)); } break; } /*TODO code along these lines would be less repetitive Class clazz = null; switch(ad.getType()){ case AttributeDefinition.STRING: clazz = null; break; case AttributeDefinition.BOOLEAN: clazz = Boolean.class; break; case AttributeDefinition.BYTE: clazz = Byte.class; break; case AttributeDefinition.DOUBLE: clazz = Double.class; break; case AttributeDefinition.FLOAT: clazz = Float.class; break; case AttributeDefinition.INTEGER: clazz = Integer.class; break; case AttributeDefinition.LONG: clazz = Long.class; break; case AttributeDefinition.SHORT: clazz = Short.class; break; case AttributeDefinition.CHARACTER: clazz = Character.class; break; } Method method = null; try{ method = clazz.getMethod("valueOf", new Class[]{String.class}); } catch(NoSuchMethodException e){ } Boolean val = null; try{ val = (Boolean) method.invoke(null, new Object[]{"true"}); } catch(IllegalAccessException e){ } catch(InvocationTargetException e){ } */ if(value != null){ props.put(ad.getName(), value); } } } //while try{ conf.update(props); } catch(IOException ioe){} } //if if(factoryPid != null){ factoryPids.put(factoryPid, ocd); } else{ pids.put(pid, ocd); } } //TODO enforce bundleLocation } private void loadLocales(){ String x = Locale.getDefault().toString(); Vector localesV = new Vector(); Enumeration localizationFiles = bundle.findEntries(locBaseDir, localizationFileBaseName + "*.properties", false); if(localizationFiles != null){ while(localizationFiles.hasMoreElements()){ URL url = (URL)localizationFiles.nextElement(); String fileName = url.getFile().substring(15); if(fileName.length() == (localizationFileBaseName + ".properties").length()){ continue; } else { int dot = fileName.lastIndexOf('.'); fileName= fileName.substring(0, dot); int underscore = fileName.indexOf('_'); fileName = fileName.substring(underscore + 1); localesV.add(fileName); } } locales = (String[]) localesV.toArray(new String[localesV.size()]); } } private Properties loadLocaleEntries(URL url){ Properties entries = new Properties(); try{ InputStream is = url.openStream(); entries.load(is); } catch(IOException e){ return entries; } return entries; } }