📄 loader.java
字号:
/* * Copyright (c) 2003, 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. */package org.knopflerfish.util.metatype;import org.osgi.framework.*;import org.osgi.service.metatype.*;import net.n3.nanoxml.*;import java.net.URL;import java.io.*;import java.util.*;import java.lang.reflect.Array;import org.knopflerfish.util.Text;/** * Helper class which loads (and saves) KF Metatype XML. * * <p> * This implementaion uses the nanoxml package. * </p> * <p> * NanoXML is distributed under the zlib/libpng license.<br> * See <a href="http://nanoxml.sourceforge.net/orig/copyright.html">http://nanoxml.sourceforge.net/orig/copyright.html</a> * for details.<br> * The full license text is also include in the kf_metatype bundle jar * </p> * Nanoxml is Copyrighted 2000-2002 Marc De Scheemaecker, All Rights * Reserved. * </p> */public class Loader { static final String METATYPE = "metatype"; static final String SERVICES = "services"; static final String FACTORIES = "factories"; static final String VALUES = "values"; static final String SCHEMA = "schema"; static final String SERVICE_PID = "service.pid"; static final String FACTORY_PID = "factory.pid"; static final String ITEM = "item"; static final String ATTR_PID = "pid"; static final String ATTR_DECS = "description"; static final String ATTR_TYPE = "type"; static final String ATTR_NAME = "name"; static final String ATTR_BASE = "base"; static final String ATTR_VALUE = "value"; static final String ATTR_ICONURL = "iconURL"; static final String ATTR_MINOCCURS = "minOccurs"; static final String ATTR_MAXOCCURS = "maxOccurs"; static final String ATTR_ARRAY = "array"; static final String XSD_NS = "http://www.w3.org/2001/XMLSchema"; static final String METATYPE_NS = "http://www.knopflerfish.org/XMLMetatype"; static final String TAG_ANNOTATION = "annotation"; static final String TAG_SIMPLETYPE = "simpleType"; static final String TAG_COMPLEXTYPE = "complexType"; static final String TAG_ELEMENT = "element"; static final String TAG_RESTRICTION = "restriction"; static final String TAG_ENUMERATION = "enumeration"; static final String TAG_DOCUMENTATION = "documentation"; static final String TAG_APPINFO = "appinfo"; static final String TAG_SEQUENCE = "sequence"; static final String BUNDLE_PROTO = "bundle://"; /** * Load a MetaTypeProvider from an XML file. */ public static MTP loadMTPFromURL(Bundle bundle, URL url) throws IOException { InputStream in = null; try { in = url.openStream(); IXMLParser parser = XMLParserFactory.createDefaultXMLParser(); IXMLReader reader = new StdXMLReader(in); parser.setReader(reader); XMLElement el = (XMLElement) parser.parse(); return loadMTP(bundle, url.toString(), el); } catch (Exception e) { e.printStackTrace(); throw new IOException("Failed to load " + url + " " + e); } finally { try { in.close(); } catch (Exception ignored) { } } } /** * load defaults from an XML file into an MTP */ public static List loadDefaultsFromURL(MTP mtp, URL url) throws IOException { InputStream in = null; try { in = url.openStream(); IXMLParser parser = XMLParserFactory.createDefaultXMLParser(); IXMLReader reader = new StdXMLReader(in); parser.setReader(reader); XMLElement el = (XMLElement) parser.parse(); if(isName(el, METATYPE_NS, VALUES)) { List propList = loadValues(mtp, el); setDefaultValues(mtp, propList); return propList; } else { for(Enumeration e = el.enumerateChildren(); e.hasMoreElements(); ) { XMLElement childEl = (XMLElement)e.nextElement(); if(isName(childEl, METATYPE_NS, VALUES)) { List propList = loadValues(mtp, childEl); setDefaultValues(mtp, propList); return propList; } } } throw new XMLException("No values tag in " + url, el); } catch (Exception e) { e.printStackTrace(); throw new IOException("Failed to load " + url + " " + e); } finally { try { in.close(); } catch (Exception ignored) { } } } /** * Load a MetaTypeProvider from an XML "config" element. * * <ol> * <li>Load all service and factory definitions into * a MetaTypeProvider instance. * <li>Load any default data * <li>Insert default data into definitions in MetaTypeProvider * using the <tt>setDefaultValues</tt> method * </ol> * */ public static MTP loadMTP(Bundle bundle, String sourceName, XMLElement el) { assertTagName(el, METATYPE_NS, METATYPE); CMConfig[] services = null; CMConfig[] factories = null; boolean bHasDefValues = false; for(Enumeration e = el.enumerateChildren(); e.hasMoreElements(); ) { XMLElement childEl = (XMLElement)e.nextElement(); if(isName(childEl, METATYPE_NS, SERVICES)) { services = parseServices(childEl, false); } else if(isName(childEl, METATYPE_NS, FACTORIES)) { factories = parseServices(childEl, true); } else if(isName(childEl, METATYPE_NS, VALUES)) { bHasDefValues = true; } else if(isName(childEl, XSD_NS, SCHEMA)) { CMConfig[] any = parseSchema(childEl); List sa = new ArrayList(); List fa = new ArrayList(); for(int i = 0; i < any.length; i++) { if(any[i].maxInstances > 1) { fa.add(any[i]); } else { sa.add(any[i]); } } services = new CMConfig[sa.size()]; sa.toArray(services); factories = new CMConfig[fa.size()]; fa.toArray(factories); } else { throw new XMLException("Unexpected element", el); } } MTP mtp = new MTP(sourceName); // Insert servcies and factory definition into MTP // default values will be default values defined by AD for(int i = 0; services != null && i < services.length; i++) { OCD ocd = new OCD(services[i].pid, services[i].pid, services[i].desc); ocd.maxInstances = 1; String iconURL = services[i].iconURL; if(iconURL != null) { try { if(bundle != null) { if(iconURL.startsWith("/")) { iconURL = BUNDLE_PROTO + "$(BID)" + iconURL; } iconURL = Text.replace(iconURL, "$(BID)", Long.toString(bundle.getBundleId())); } ocd.setIconURL(iconURL); } catch (Exception e) { System.err.println("Failed to set icon url: " + e); } } for(int j = 0; j < services[i].ads.length; j++) { ocd.add(services[i].ads[j], services[i].ads[j].isOptional() ? ObjectClassDefinition.OPTIONAL : ObjectClassDefinition.REQUIRED); } mtp.addService(services[i].pid, ocd); } for(int i = 0; factories != null && i < factories.length; i++) { OCD ocd = new OCD(factories[i].pid, factories[i].pid, factories[i].desc); ocd.maxInstances = factories[i].maxInstances; if(factories[i].iconURL != null) { try { ocd.setIconURL(factories[i].iconURL); } catch (Exception e) { System.err.println("Failed to set icon url: "+ e); } } for(int j = 0; j < factories[i].ads.length; j++) { ocd.add(factories[i].ads[j], ObjectClassDefinition.REQUIRED); } mtp.addFactory(factories[i].pid, ocd); } // Overwrite MTP default values with values found in // DEFAULTVALUES section in source XML if(bHasDefValues) { for(Enumeration e = el.enumerateChildren(); e.hasMoreElements(); ) { XMLElement childEl = (XMLElement)e.nextElement(); if(isName(childEl, METATYPE_NS, VALUES)) { List propList = loadValues(mtp, childEl); setDefaultValues(mtp, propList); } } } return mtp; } /** * Overwrite default values in MTP using a set of dictionaries. * * @param mtp MetaTypeProvider containing instances of <tt>AD</tt> * @param propList List of Dictionary */ public static void setDefaultValues(MetaTypeProvider mtp, List propList) { for(Iterator it = propList.iterator(); it.hasNext();) { Dictionary props = (Dictionary)it.next(); String pid = (String)props.get(SERVICE_PID); if(pid == null) { pid = (String)props.get("factory.pid"); } ObjectClassDefinition ocd = null; try { ocd = mtp.getObjectClassDefinition(pid, null); } catch (Exception ignored) { } if(ocd == null) { throw new IllegalArgumentException("No definition for pid '" + pid + "'"); } else { AttributeDefinition[] ads = ocd.getAttributeDefinitions(ObjectClassDefinition.ALL); for(int i = 0; ads != null && i < ads.length; i++) { Object val = props.get(ads[i].getID()); if(!(ads[i] instanceof AD)) { throw new IllegalArgumentException("AttributeDefinitions must be instances of AD, otherwise default values cannot be set"); } AD ad = (AD)ads[i]; if(val instanceof Vector) { ad.setDefaultValue(toStringArray((Vector)val)); } else if(val.getClass().isArray()) { ad.setDefaultValue(toStringArray((Object[])val)); } else { ad.setDefaultValue(new String[] { val.toString() }); } } } } } /** * @return String (pid) -> Dictionary */ public static List loadValues(MetaTypeProvider mtp, XMLElement el) { // assertTagName(el, DEFAULTVALUES); List propList = new ArrayList(); // String (pid) -> Integer (count) Map countMap = new HashMap(); for(Enumeration e = el.enumerateChildren(); e.hasMoreElements(); ) { XMLElement childEl = (XMLElement)e.nextElement(); String pid = childEl.getName(); ObjectClassDefinition ocd = null; try { ocd = mtp.getObjectClassDefinition(pid, null); } catch (Exception ignored) { } if(ocd == null) { throw new XMLException("Undefined pid '" + pid + "'", childEl); } Dictionary props = loadValues(ocd.getAttributeDefinitions(ObjectClassDefinition.ALL), childEl); int maxInstances = 1; if(ocd instanceof OCD) { maxInstances = ((OCD)ocd).maxInstances; } Integer count = (Integer)countMap.get(pid); if(count == null) { count = new Integer(0); } count = new Integer(count.intValue() + 1); if(count.intValue() > maxInstances) { throw new XMLException("PID " + pid + " can only have " + maxInstances + " instance(s), found " + count, el); } countMap.put(pid, count); props.put(maxInstances > 1 ? "factory.pid" : SERVICE_PID, pid); propList.add(props); } return propList; } public static Dictionary loadValues(AttributeDefinition[] attrs, XMLElement el) { if(attrs == null) { throw new NullPointerException("attrs array cannot be null"); } Hashtable props = new Hashtable(); for(Enumeration e = el.enumerateChildren(); e.hasMoreElements(); ) { XMLElement childEl = (XMLElement)e.nextElement(); String id = childEl.getFullName(); AttributeDefinition attr = null; // System.out.println("load id=" + id); for(int i = 0; attr == null && i < attrs.length; i++) { // System.out.println(i + ": " + attrs[i]); if(id.equals(attrs[i].getID())) { attr = attrs[i]; } } if(attr == null) { throw new XMLException("Undefined id '" + id + "'", childEl); } Object val = loadValue(attr, childEl); props.put(id, val); } // Verify that all attributes are found for(int i = 0; i < attrs.length; i++) { if(!props.containsKey(attrs[i].getID())) { throw new XMLException("Missing attribute id '" + attrs[i].getID() + "'", el); } } return props; } /** * Load a java object from an XML element using type info in the * specified definition. * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -