0001: /*
0002: * Copyright 2001-2006 C:1 Financial Services GmbH
0003: *
0004: * This software is free software; you can redistribute it and/or
0005: * modify it under the terms of the GNU Lesser General Public
0006: * License Version 2.1, as published by the Free Software Foundation.
0007: *
0008: * This software is distributed in the hope that it will be useful,
0009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0011: * Lesser General Public License for more details.
0012: *
0013: * You should have received a copy of the GNU Lesser General Public
0014: * License along with this library; if not, write to the Free Software
0015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
0016: */
0017:
0018: package de.finix.contelligent.core;
0019:
0020: import java.io.IOException;
0021: import java.io.Writer;
0022: import java.net.URL;
0023: import java.net.URLClassLoader;
0024: import java.security.CodeSource;
0025: import java.security.PermissionCollection;
0026: import java.security.Permissions;
0027: import java.util.ArrayList;
0028: import java.util.Collection;
0029: import java.util.Collections;
0030: import java.util.HashMap;
0031: import java.util.HashSet;
0032: import java.util.Iterator;
0033: import java.util.LinkedList;
0034: import java.util.List;
0035: import java.util.Map;
0036: import java.util.Set;
0037: import java.util.Vector;
0038:
0039: import javax.transaction.Status;
0040:
0041: import de.finix.contelligent.Component;
0042: import de.finix.contelligent.ComponentManager;
0043: import de.finix.contelligent.ComponentPath;
0044: import de.finix.contelligent.Type;
0045: import de.finix.contelligent.exception.ContelligentExceptionID;
0046: import de.finix.contelligent.exception.TypeException;
0047: import de.finix.contelligent.exception.UnknownTypeException;
0048: import de.finix.contelligent.logging.LoggingService;
0049: import de.finix.contelligent.persistence.TypePersistenceAdapter;
0050: import de.finix.contelligent.persistence.TypeProperty;
0051: import de.finix.contelligent.xml.elements.TypeElement;
0052: import de.finix.contelligent.xml.elements.TypePropertyElement;
0053: import de.finix.contelligent.xml.export.TypeXMLWriter;
0054:
0055: /**
0056: * This class is a factory for Contelligent {@link Component components} and
0057: * caches all {@link TypeImpl type-information}. Only the component-managers
0058: * should directly communicate with it. <BR>
0059: */
0060: public class ComponentFactoryImpl extends URLCL implements
0061: ComponentFactory, TxSynchronization {
0062: final static org.apache.log4j.Logger log = LoggingService
0063: .getLogger(ComponentFactoryImpl.class);
0064:
0065: final private TypePersistenceAdapter typeAdapter;
0066:
0067: final private PropertyHandler propertyHandler;
0068:
0069: /**
0070: * contains entries (String/TypeImpl) mapping the name of a type to its
0071: * type-info
0072: */
0073: private Map typeMap = new HashMap();
0074:
0075: /**
0076: * Contains (ComponentPath/TypeImpl) mapping the path of a blueprint
0077: * definition to the corresponding TypeImpl.
0078: */
0079: private Map blueprintMap = new HashMap();
0080:
0081: /**
0082: * These two thread-local maps are either null or contain all entries from
0083: * the corresponding global map (typeMap or blueprintMap) plus any
0084: * modifications made within the current transaction.
0085: */
0086: private ThreadLocal effectiveTypeMap = new ThreadLocal();
0087:
0088: private ThreadLocal effectiveBlueprintMap = new ThreadLocal();
0089:
0090: private ThreadLocal addedTypes = new ThreadLocal();
0091:
0092: private ThreadLocal removedTypes = new ThreadLocal();
0093:
0094: private ThreadLocal deferInit = new ThreadLocal();
0095:
0096: /*
0097: * (non-Javadoc)
0098: *
0099: * @see java.security.SecureClassLoader#getPermissions(java.security.CodeSource)
0100: */
0101: protected PermissionCollection getPermissions(CodeSource codesource) {
0102: Permissions perms = new Permissions();
0103: // perms.add(new AllPermission());
0104: // perms.add(new
0105: // RuntimePermission("org.jboss.security.SecurityAssociation.getPrincipalInfo");
0106: return perms;
0107: }
0108:
0109: /**
0110: * Creates a new <code>ComponentFactoryImpl</code> instance and loads all
0111: * types from the database adapter and {@link #initAllTypes initializes}
0112: * them.
0113: *
0114: * @param urls
0115: * an <code>URL[]</code> value
0116: * @param parent
0117: * a <code>ClassLoader</code> value
0118: * @param typeAdapter
0119: * a <code>TypePersistenceAdapter</code> value
0120: * @param propertyHandler
0121: * a <code>PropertyHandler</code> value
0122: */
0123: public ComponentFactoryImpl(final URL[] urls,
0124: final ClassLoader parent,
0125: TypePersistenceAdapter typeAdapter,
0126: PropertyHandler propertyHandler) {
0127: super (urls, parent);
0128: /*
0129: * ClassLoader cur = this; log.info("created ComponentFactoryImpl with
0130: * classLoader Hierarchy: ");
0131: *
0132: * do { log.info(" - "+cur); cur = cur.getParent(); }while(cur!=null);
0133: */
0134:
0135: log
0136: .debug("<init> - super() called, now beginning own initialization ...");
0137: for (int i = 0; i < urls.length; i++) {
0138: log.debug("<init> - ... URL '" + urls[i] + "' added.");
0139: }
0140: this .propertyHandler = propertyHandler;
0141: this .typeAdapter = typeAdapter;
0142:
0143: initTypes();
0144: log.debug("<init> - done.");
0145: }
0146:
0147: synchronized void initTypes() {
0148: Map oldTypeMap = typeMap;
0149: Map oldBlueprintMap = blueprintMap;
0150: typeMap = new HashMap();
0151:
0152: try {
0153: log.info("loading all types from persistence store ...");
0154: String[] typeNames = typeAdapter.getNames();
0155: for (int i = 0; i < typeNames.length; i++) {
0156: String typeName = typeNames[i];
0157: TypeImpl type = typeAdapter.load(typeName);
0158: typeMap.put(typeName, type);
0159: }
0160: Iterator names = typeMap.keySet().iterator();
0161: while (names.hasNext()) {
0162: String typeName = (String) names.next();
0163: TypeImpl type = (TypeImpl) typeMap.get(typeName);
0164: if (type.getClassName() != null) {
0165: if (type.getClassName().startsWith("!")) {
0166: try {
0167: Class clazz = getClassForType(type);
0168: Object t = clazz.newInstance();
0169: } catch (Exception e) {
0170: log.warn("Unable to preload class: "
0171: + type.getClassName(), e);
0172: }
0173: }
0174: }
0175: }
0176: log.info("initializing types ...");
0177: blueprintMap = initAllTypes(typeMap);
0178: log.debug("intialization done.");
0179: } catch (TypeException e) {
0180: log.error("exception while loading types: ", e);
0181: typeMap = oldTypeMap;
0182: blueprintMap = oldBlueprintMap;
0183: // throw new ComponentPersistenceException("TypeDBAdapter '"+name+"'
0184: // - exception during initialization of types!", e);
0185: }
0186: }
0187:
0188: /**
0189: * Implementation of {@link TxSynchronization#beforeCompletion} which does
0190: * currently nothing but returning true.
0191: */
0192: public boolean beforeCompletion() {
0193: return true;
0194: }
0195:
0196: /**
0197: * Implementation of {@link TxSynchronization#afterCompletion}. Here any
0198: * modifications made within the current transaction are merged into the
0199: * global maps. (by simply switching the maps)
0200: */
0201: public void afterCompletion(int status) {
0202: Set added = getAddedTypes(false);
0203: Set removed = getRemovedTypes(false);
0204:
0205: if (added != null || removed != null) {
0206: if (status == Status.STATUS_COMMITTED) {
0207: synchronized (this ) {
0208: Map newTypeMap = (Map) effectiveTypeMap.get();
0209:
0210: Iterator iterator;
0211:
0212: if (added != null) {
0213: iterator = added.iterator();
0214:
0215: while (iterator.hasNext()) {
0216: String typeName = (String) iterator.next();
0217: typeMap.put(typeName, newTypeMap
0218: .get(typeName));
0219: }
0220: }
0221: if (removed != null) {
0222: iterator = removed.iterator();
0223:
0224: while (iterator.hasNext()) {
0225: String typeName = (String) iterator.next();
0226: typeMap.remove(typeName);
0227: }
0228: }
0229: blueprintMap = initAllTypes(typeMap);
0230: }
0231: clean();
0232: }
0233: }
0234: }
0235:
0236: public void clean() {
0237: effectiveTypeMap.set(null);
0238: effectiveBlueprintMap.set(null);
0239: addedTypes.set(null);
0240: removedTypes.set(null);
0241: }
0242:
0243: /**
0244: * Implementation of
0245: * {@link de.finix.contelligent.core.ComponentFactory#deleteType}.
0246: */
0247: public void deleteType(String typeName)
0248: throws UnknownTypeException, TypeException {
0249: if (!exists(typeName)) {
0250: throw new UnknownTypeException("Type '" + typeName
0251: + "' does not exist.");
0252: }
0253: if (!getSubTypeNames(typeName).isEmpty()) {
0254: throw new TypeException(
0255: ContelligentExceptionID.type_subtypesExist,
0256: new Object[] { typeName });
0257: }
0258: typeAdapter.remove(typeName);
0259: getRemovedTypes(true).add(typeName);
0260: storeModification(typeName, null, false);
0261:
0262: }
0263:
0264: boolean deleteTypeRaw(String typeName) throws UnknownTypeException,
0265: TypeException {
0266: if (!exists(typeName)) {
0267: throw new UnknownTypeException("Type '" + typeName
0268: + "' does not exist.");
0269: }
0270: boolean subtypes = !getSubTypeNames(typeName).isEmpty();
0271: typeAdapter.remove(typeName);
0272: getRemovedTypes(true).add(typeName);
0273: storeModification(typeName, null, true);
0274: return subtypes;
0275: }
0276:
0277: boolean flagTypeForUpgrade(String typeName)
0278: throws UnknownTypeException, TypeException {
0279: if (!exists(typeName)) {
0280: throw new UnknownTypeException("Type '" + typeName
0281: + "' does not exist.");
0282: }
0283: boolean subtypes = !getSubTypeNames(typeName).isEmpty();
0284: typeAdapter.flagForUpgrade(typeName);
0285: return subtypes;
0286: }
0287:
0288: void checkUpgradedTypes() throws TypeException {
0289: typeAdapter.checkForUpgrades();
0290: }
0291:
0292: /**
0293: * Implementation of {@link ComponentFactory#renameType}.
0294: */
0295: public void renameType(String typeName, String newtypeName)
0296: throws TypeException {
0297: TypeImpl type = (TypeImpl) getType(typeName); // throws
0298: // UnknownTypeException
0299: // if not existent
0300: if (exists(newtypeName)) {
0301: throw new TypeException(
0302: ContelligentExceptionID.type_alreadyExist,
0303: new Object[] { newtypeName });
0304: }
0305: if (!getSubTypeNames(typeName).isEmpty()) {
0306: throw new TypeException(
0307: ContelligentExceptionID.type_subtypesExist,
0308: new Object[] { typeName });
0309: }
0310:
0311: try {
0312: typeAdapter.rename(typeName, newtypeName);
0313: type.setName(newtypeName);
0314: storeModification(typeName, null, false);
0315: storeModification(newtypeName, type, false);
0316: getRemovedTypes(true).add(typeName);
0317: getAddedTypes(true).add(newtypeName);
0318: } finally {
0319: // Cleanup; not really needed if everything went well, but just
0320: // in case...
0321: initTypes();
0322: }
0323: }
0324:
0325: /**
0326: * Implementation of {@link ComponentFactory#getType}.
0327: */
0328: public Type getType(String typeName) throws UnknownTypeException {
0329: Type type = (Type) getTypeMap().get(typeName);
0330: if (type != null) {
0331: return type;
0332: } else {
0333: // initTypes(); // reload type hierarchy
0334: // type = (Type)getTypeMap().get(typeName);
0335: // if (type!=null) {
0336: // return type;
0337: // }
0338: log.debug("getType() - unknown type '" + typeName + "'!");
0339: throw new UnknownTypeException("Unknown type '" + typeName
0340: + "'.");
0341: }
0342: }
0343:
0344: /**
0345: * Implementation of {@link ComponentFactory#isSubType}.
0346: */
0347: public boolean isSubType(Type maybeSubType,
0348: String maybeSuperTypeName) {
0349: String super TypeName = maybeSubType.getSuperTypeName();
0350: if (super TypeName == null) {
0351: // if it has no super type it can hardly be sub type of anything ;)
0352: return false;
0353: } else if (super TypeName.equals(maybeSuperTypeName)) {
0354: return true;
0355: } else {
0356: try {
0357: Type super Type = getType(super TypeName);
0358: return isSubType(super Type, maybeSuperTypeName);
0359: } catch (UnknownTypeException e) {
0360: if (log.isDebugEnabled()) {
0361: log.debug("isSubType() - can not tell if "
0362: + maybeSubType + " is a subtype of "
0363: + maybeSuperTypeName);
0364: }
0365: return false;
0366: }
0367: }
0368: }
0369:
0370: /**
0371: * Implementation of {@link ComponentFactory#exists}.
0372: */
0373: public boolean exists(String typeName) {
0374: Map map = getTypeMap();
0375: return map.containsKey(typeName);
0376: }
0377:
0378: /**
0379: * Implementation of {@link ComponentFactory#getSubTypeNames}.
0380: */
0381: public Set getSubTypeNames(String typeName) {
0382: Map map = getTypeMap();
0383: Set answer = new HashSet();
0384: Iterator iterator = map.values().iterator();
0385: while (iterator.hasNext()) {
0386: Type type = (Type) iterator.next();
0387: if (isSubType(type, typeName)) {
0388: answer.add(type.getName());
0389: }
0390: }
0391: return answer;
0392: }
0393:
0394: /**
0395: * Implementation of {@link ComponentFactory#typeNames}.
0396: */
0397: public Set typeNames() {
0398: Map map = getTypeMap();
0399: Set nameSet = new HashSet(map.size());
0400: nameSet.addAll(map.keySet());
0401: return nameSet;
0402: }
0403:
0404: /**
0405: * Implementation of {@link ComponentFactory#exportTypes}.
0406: */
0407: public void exportTypes(Writer writer, boolean omitHeader,
0408: String prefix) throws IOException {
0409: TypeXMLWriter typeXMLWriter = new TypeXMLWriter();
0410: Collection types;
0411: if (prefix == null || prefix.trim().length() == 0) {
0412: types = getTypeMap().values();
0413: } else {
0414: types = new LinkedList();
0415: Iterator entries = getTypeMap().entrySet().iterator();
0416: while (entries.hasNext()) {
0417: Map.Entry entry = (Map.Entry) entries.next();
0418: if (((String) entry.getKey()).startsWith(prefix)) {
0419: types.add(entry.getValue());
0420: }
0421: }
0422: }
0423: // sort according to the type hierarchy:
0424: List sorted = sortTypes(types);
0425: typeXMLWriter.write((Type[]) sorted.toArray(new Type[sorted
0426: .size()]), writer, omitHeader);
0427: }
0428:
0429: /**
0430: * Returns a list containing all given types sorted according to their
0431: * inheritance hierarchy.
0432: *
0433: * @param types
0434: * a <code>Collection</code> of <code>Type</code> instances.
0435: * @return a <code>List</code> value
0436: */
0437: public List sortTypes(Collection types) {
0438: List sorted = new LinkedList();
0439: Iterator t = types.iterator();
0440: while (t.hasNext()) {
0441: Type type = (Type) t.next();
0442: int i = 0, size = sorted.size();
0443: boolean added = false;
0444: while (!added && i < size) {
0445: if (isSubType((Type) sorted.get(i), type.getName())) {
0446: sorted.add(i, type);
0447: added = true;
0448: } else {
0449: i++;
0450: }
0451: }
0452: if (!added) {
0453: sorted.add(type);
0454: }
0455: }
0456: return sorted;
0457: }
0458:
0459: public boolean isBlueprintPath(ComponentPath path) {
0460: return getBlueprintMap().containsKey(path);
0461: }
0462:
0463: public boolean containsBlueprintPath(ComponentPath path) {
0464: if (isBlueprintPath(path)) {
0465: return true;
0466: } else {
0467: Iterator paths = getBlueprintMap().keySet().iterator();
0468: while (paths.hasNext()) {
0469: ComponentPath current = (ComponentPath) paths.next();
0470: if (current.isSubPathOf(path)) {
0471: return true;
0472: }
0473: }
0474: return false;
0475: }
0476: }
0477:
0478: public Type getBlueprintType(ComponentPath path) {
0479: return (Type) getBlueprintMap().get(path);
0480: }
0481:
0482: public void validateBlueprintTypes(ComponentManager componentManager)
0483: throws TypeException {
0484: Iterator iterator = getBlueprintMap().values().iterator();
0485: while (iterator.hasNext()) {
0486: Type type = (Type) iterator.next();
0487: if (!componentManager.componentExists(type
0488: .getBlueprintPath())) {
0489: throw new TypeException(
0490: ContelligentExceptionID.type_missingBlueprint,
0491: new Object[] { type.getName(),
0492: type.getBlueprintPath() });
0493: }
0494: }
0495: }
0496:
0497: /**
0498: * Initializes a new {@link TypeImpl type}. If the type is derived from
0499: * another one the specified map is used to search for the super types. If a
0500: * super type is not found or the class specified by the type can not be
0501: * found a <code>TypeCreationException</code> is thrown. Note that the
0502: * type itself is not added to this map! <BR>
0503: * If <tt>checkProperties</tt> is true the properties are checked for
0504: * incompatible overwrites. An overwritten property must define the same
0505: * {@link PropertyType property-type} as defined by the super-type this
0506: * property was first defined in. A change of the property-mode is only
0507: * allowed if the type extends another type. Otherwise the overwrite is
0508: * considered as incompatible and a <code>TypeCreationException</code> is
0509: * thrown. <BR>
0510: * See {@link #initAllTypes} for details about type-initialization.
0511: *
0512: * @param type
0513: * a non-null <code>TypeImpl</code> value containing the type
0514: * to initialize.
0515: * @param typeName2type
0516: * a <code>Map</code> containing (String,TypeImpl) entries
0517: * mapping the name of a type to its corresponding type-info.
0518: * @param checkProperties
0519: * a <code>boolean</code> value
0520: * @return a <code>boolean</code> value, true if the initialized type
0521: * defines a blueprint
0522: * @exception TypeException
0523: * if an error occurs
0524: */
0525: private boolean initType(TypeImpl type, Map typeName2type,
0526: boolean checkProperties) throws TypeException {
0527: final String typeName = type.getName();
0528: if (log.isDebugEnabled()) {
0529: log.debug("initType() - trying to initialize type '"
0530: + typeName + "' ...");
0531: }
0532: final LinkedList mapList = new LinkedList();
0533: mapList.addFirst(type.getOriginalPropertyMap());
0534:
0535: String super TypeName = type.getSuperTypeName();
0536: type.setSuperType((Type) typeName2type.get(super TypeName));
0537: while (super TypeName != null) {
0538: TypeImpl super Type = (TypeImpl) typeName2type
0539: .get(super TypeName);
0540: if (super Type == null) {
0541: log.error("initType() - can not initialize type '"
0542: + typeName
0543: + "' because one of its super-types ('"
0544: + super TypeName + "') does not exists!");
0545: throw new TypeException(
0546: ContelligentExceptionID.type_missingSupertype,
0547: new Object[] { typeName, super TypeName });
0548: }
0549: mapList.addFirst(super Type.getOriginalPropertyMap());
0550:
0551: if (type.getClassName() == null) {
0552: type.setClassName(super Type.getClassName());
0553: if (log.isDebugEnabled()) {
0554: log
0555: .debug("initType() - implementation class of type '"
0556: + typeName
0557: + "' taken from super-type '"
0558: + super TypeName
0559: + "': class="
0560: + super Type.getClassName() + ".");
0561: }
0562: }
0563: super TypeName = super Type.getSuperTypeName();
0564: }
0565:
0566: if (!type.isBlueprint()) {
0567: final String typeClassName = type.getClassName();
0568: if (typeClassName == null) {
0569: log
0570: .error("initType() - can not initialize type '"
0571: + typeName
0572: + "' because the implementation class is null!");
0573: throw new TypeException(
0574: ContelligentExceptionID.type_missingImpl,
0575: new Object[] { typeName, null });
0576: }
0577: }
0578:
0579: // now create a new map with accumulated type-properties:
0580: Map mergedPropertyMap = new HashMap();
0581: Iterator mapIt = mapList.iterator();
0582: int errors = 0;
0583: while (mapIt.hasNext()) {
0584: Map otherTypePropertyMap = (Map) mapIt.next();
0585: if (!checkProperties) {
0586: mergedPropertyMap.putAll(otherTypePropertyMap);
0587: } else {
0588: Iterator keys = otherTypePropertyMap.keySet()
0589: .iterator();
0590: while (keys.hasNext()) {
0591: Object key = keys.next();
0592: boolean error = false;
0593: if (mergedPropertyMap.containsKey(key)) {
0594: TypeProperty fromSuper = (TypeProperty) mergedPropertyMap
0595: .get(key);
0596: TypeProperty overwritten = (TypeProperty) otherTypePropertyMap
0597: .get(key);
0598: if ((type.restrictsOnly() || overwritten
0599: .inheritType())
0600: && !(fromSuper.getPropertyType()
0601: .equals(overwritten
0602: .getPropertyType()))) {
0603: log
0604: .error("initType() - type '"
0605: + overwritten
0606: .getDefiningTypeName()
0607: + "' overwrites property '"
0608: + fromSuper.getName()
0609: + "' of type '"
0610: + fromSuper
0611: .getDefiningTypeName()
0612: + "' but the property-type doesn't match!");
0613: error = true;
0614: errors++;
0615: }
0616: if ((type.restrictsOnly() || overwritten
0617: .inheritMode())
0618: && !(fromSuper.getMode()
0619: .equals(overwritten.getMode()))) {
0620: log.error("initType() - type '"
0621: + overwritten.getDefiningTypeName()
0622: + "' overwrites property '"
0623: + fromSuper.getName()
0624: + "' of restricted type '"
0625: + fromSuper.getDefiningTypeName()
0626: + "' but the mode doesn't match!");
0627: error = true;
0628: errors++;
0629: }
0630: }
0631: if (!error) {
0632: mergedPropertyMap.put(key, otherTypePropertyMap
0633: .get(key));
0634: } else {
0635: if (log.isDebugEnabled()) {
0636: log
0637: .debug("initType() - skipping property '"
0638: + otherTypePropertyMap
0639: .get(key) + "' ...");
0640: }
0641: }
0642: }
0643: }
0644: }
0645: if (errors == 0) {
0646: type.setMergedPropertyMap(mergedPropertyMap);
0647: if (log.isDebugEnabled()) {
0648: log
0649: .debug("initType() - ... type '"
0650: + typeName
0651: + "' (type-info="
0652: + type
0653: + ") successfully initialized and put into map.");
0654: }
0655: return (type.isBlueprint());
0656: } else {
0657: log.error("initType() - ... there were " + errors
0658: + " errors during initialization of type '"
0659: + typeName + "'! Type NOT initialized.");
0660: throw new TypeException(
0661: ContelligentExceptionID.type_properties,
0662: new Object[] { typeName, new Integer(errors) });
0663: }
0664: }
0665:
0666: /**
0667: * Initializes all types contained in the given map. The map is expected to
0668: * contain (String,TypeImpl) entries mapping the name of a type to its
0669: * corresponding {@link TypeImpl type-info}. <BR>
0670: * If any super type of a specific type can't be found in the map or if the
0671: * implementation class of a type can't be found a
0672: * ComponentPersistenceException is thrown. <BR>
0673: *
0674: * What does it mean to initialize a type? <BR>
0675: *
0676: * Because type can be derived from one another we must merge the properties
0677: * of a type hierarchie so that the properties of a sub-type always
0678: * overwrite those of a super-type. In addition we set the effective
0679: * implementation class in the Type instance and remember the originally
0680: * defined classname and property-map of the type in its corresponding
0681: * type-info.
0682: *
0683: * @param typeMap
0684: * a <code>Map</code> containing (String,InternalTypeHolder)
0685: * entries mapping the name of a type to its corresponding
0686: * type-info.
0687: * @return a <code>Map</code> containing (ComponentPath, TypeImpl) entries
0688: * mapping the path of a component defining a blueprint to the
0689: * corresponding type definition.
0690: */
0691: private Map initAllTypes(Map typeMap) {
0692: List failedTypes = new Vector();
0693:
0694: Iterator types = typeMap.values().iterator();
0695: if (log.isDebugEnabled()) {
0696: log.debug("initAllTypes() - will initialize "
0697: + typeMap.size() + " type infos ...");
0698: }
0699: Map blueprints = new HashMap();
0700: while (types.hasNext()) {
0701: TypeImpl type = (TypeImpl) types.next();
0702: try {
0703: boolean isBlueprint = initType(type, typeMap, true); // true:
0704: // check
0705: // properties
0706: // for
0707: // incompatible
0708: // overwrites
0709: if (isBlueprint) {
0710: blueprints.put(type.getBlueprintPath(), type);
0711: }
0712: } catch (TypeException e) {
0713: log
0714: .error("initAllTypes() - could not initalize type '"
0715: + type.getName()
0716: + "'! This type will be removed but trying to initialize the other types ...");
0717: failedTypes.add(type.getName());
0718: types.remove(); // removeType the buggy Type !
0719: }
0720: }
0721: if (!failedTypes.isEmpty()) {
0722: log
0723: .error("[TypeDBAdapter]:initAllTypes() - could not initalize the following types: "
0724: + failedTypes);
0725: }
0726: return blueprints;
0727: }
0728:
0729: /**
0730: * Implementation of {@link ComponentFactory#getURLs}. This implementation
0731: * simply uses the {@link URLClassLoader#getURLs} method of its super class.
0732: *
0733: * @return a <code>List</code> value
0734: * @see ComponentFactory#getURLs
0735: * @see URLClassLoader#getURLs
0736: */
0737: public URL[] getURLs() {
0738: return super .getURLs();
0739: }
0740:
0741: /**
0742: * Implementation of {@link ComponentFactory#addURL}. This implementation
0743: * simply uses the {@link URLClassLoader#addURL} method of its super class.
0744: * XXX: this is currently not in use
0745: *
0746: * @param url
0747: * an <code>URL</code> value
0748: * @see ComponentFactory#addURL
0749: * @see URLClassLoader#addURL
0750: *
0751: *
0752: * public void addURL(URL url) { super.addURL(url); }/
0753: *
0754: *
0755: * /** Implementation of {@link ComponentFactory#createInstance(Type)}.
0756: */
0757: public Component createInstance(Type type) throws TypeException {
0758: return createInstance(type, null);
0759: }
0760:
0761: /**
0762: * Implementation of {@link ComponentFactory#createInstance(Type, Map)}.
0763: */
0764: public Component createInstance(Type type, Map propertyMap)
0765: throws TypeException {
0766: return createInstance((TypeImpl) type, propertyMap, true);
0767: }
0768:
0769: /**
0770: * Implementation of {@link ComponentFactory#createRawInstance}.
0771: */
0772: public Component createRawInstance(Type type) throws TypeException {
0773: return createInstance((TypeImpl) type, null, false);
0774: }
0775:
0776: private Class getClassForType(TypeImpl type) throws TypeException {
0777: final boolean debugEnabled = log.isDebugEnabled();
0778:
0779: String className = type.getClassName();
0780: try {
0781: Class classImpl = null;
0782: synchronized (type) {
0783: // Synchronized to prevent multiple loading
0784: // of the same class on startup; only
0785: // for performance reasons.
0786: classImpl = type.getTypeClass();
0787: if (classImpl == null) {
0788: className = type.getClassName();
0789: if (className != null) {
0790: if (className.startsWith("!")) {
0791: className = className.substring(1);
0792: }
0793: }
0794: if (debugEnabled) {
0795: log
0796: .debug("createInstance() - trying to create instance of class '"
0797: + className + "' ...");
0798: }
0799:
0800: // This is the one we dont want to call unnecessarily
0801: classImpl = loadClass(className);
0802: if (debugEnabled) {
0803: log
0804: .debug("createInstance() - ... found class '"
0805: + classImpl + "' ...");
0806: }
0807: // Store the class for future use and also initialize
0808: // properties
0809: type.setTypeClass(classImpl);
0810:
0811: // Now make sure all supertypes up to Component are
0812: // initialized
0813: String super TypeName = type.getSuperTypeName();
0814: if (super TypeName != null) {
0815: TypeImpl super TypeImpl = (TypeImpl) getTypeMap()
0816: .get(super TypeName);
0817: getClassForType(super TypeImpl);
0818: }
0819: }
0820: }
0821: return classImpl;
0822: } catch (NoClassDefFoundError e) {
0823: log.error("createInstance() - Unknown class '" + className
0824: + "': ", e);
0825: throw new TypeException(
0826: ContelligentExceptionID.type_missingImpl,
0827: new Object[] { type.getName(), className });
0828: } catch (ClassNotFoundException e) {
0829: log.error("createInstance() - Unknown class '" + className
0830: + "': ", e);
0831: throw new TypeException(
0832: ContelligentExceptionID.type_missingImpl,
0833: new Object[] { type.getName(), className });
0834: }
0835: }
0836:
0837: /**
0838: * Creates a new instance of the given type and sets the properties if param
0839: * <tt>setProperties</tt> is true.
0840: */
0841: private Component createInstance(TypeImpl type, Map propertyMap,
0842: boolean setProperties) throws TypeException {
0843: final boolean debugEnabled = log.isDebugEnabled();
0844: if (debugEnabled)
0845: log
0846: .debug("createInstance() - trying to create instance of type '"
0847: + type + "' ...");
0848:
0849: Class classImpl = getClassForType(type);
0850:
0851: try {
0852: Component component = (Component) classImpl.newInstance();
0853:
0854: if (setProperties) {
0855: type.setProperties(component, propertyMap);
0856: }
0857: if (debugEnabled) {
0858: log
0859: .debug("createInstance() - ... instance created ...");
0860: }
0861: return component;
0862: } catch (InstantiationException e) {
0863: log.error("createInstance() - InstantiationException ", e);
0864: throw new TypeException(
0865: ContelligentExceptionID.type_missingImpl,
0866: new Object[] { type.getName(), classImpl.getName() });
0867: } catch (IllegalAccessException e) {
0868: log.error("createInstance() - IllegalAccessException ", e);
0869: throw new TypeException(
0870: ContelligentExceptionID.type_missingImpl,
0871: new Object[] { type.getName(), classImpl.getName() });
0872: }
0873: }
0874:
0875: // during run of this method no access should happen!
0876: public void createTypes(List typeList) throws TypeException,
0877: UnknownTypeException {
0878: Map typeMap = getTypeMap();
0879: if (!typeMap.isEmpty()) {
0880: throw new TypeException();
0881: }
0882: Iterator types = typeList.iterator();
0883: while (types.hasNext()) {
0884: TypeElement typeElement = (TypeElement) types.next();
0885: try {
0886: TypeImpl type = createTypeImpl(typeElement);
0887: typeAdapter.write(type);
0888: typeMap.put(type.getName(), type);
0889: } catch (Exception e) {
0890: log.error("createTypes() - Exception: ", e);
0891: }
0892: }
0893: blueprintMap = initAllTypes(typeMap);
0894: log.info("createTypes() - ... successfully imported "
0895: + typeList.size() + " types.");
0896: }
0897:
0898: // XXX is used for both creation and updating
0899: public Type createType(TypeElement typeDefinition)
0900: throws TypeException, UnknownTypeException {
0901: final boolean debugEnabled = log.isDebugEnabled();
0902: String typeName = null;
0903: try {
0904: typeName = typeDefinition.getName();
0905: String super TypeName = null;
0906: String typeClassName = null;
0907: if (typeDefinition.getExtendType() != null) {
0908: super TypeName = typeDefinition.getExtendType();
0909: typeClassName = typeDefinition.getExtendClassImpl();
0910: } else if (typeDefinition.getRestrictType() != null) {
0911: super TypeName = typeDefinition.getRestrictType();
0912: } else {
0913: typeClassName = typeDefinition.getClassImpl();
0914: }
0915:
0916: Map typePropertyMap = new HashMap(); // a map containing
0917: // (String/TypeProperty)
0918: // pairs
0919: Iterator it = typeDefinition.getPropertyElementList()
0920: .iterator();
0921: while (it.hasNext()) {
0922: TypePropertyElement tpElement = (TypePropertyElement) it
0923: .next();
0924: TypeProperty typeProperty = propertyHandler
0925: .createTypeProperty(tpElement);
0926: typeProperty.setDefiningTypeName(typeName);
0927: typePropertyMap.put(typeProperty.getName(),
0928: typeProperty);
0929: }
0930: boolean restrictsOnly = (super TypeName != null && typeClassName == null);
0931: ComponentPath blueprintPath = (typeDefinition
0932: .getBlueprintPath() != null ? new ComponentPath(
0933: typeDefinition.getBlueprintPath()) : null);
0934: TypeImpl toImport = new TypeImpl(-1, typeName,
0935: typeDefinition.getGroup(), super TypeName,
0936: typeDefinition.getMetainfoElement(),
0937: typePropertyMap, null, typeClassName,
0938: restrictsOnly, blueprintPath);
0939:
0940: typeAdapter.write(toImport);
0941:
0942: storeModification(typeName, toImport, false);
0943: getAddedTypes(true).add(typeName);
0944:
0945: if (debugEnabled) {
0946: log
0947: .debug("createType() - ... successfully created type '"
0948: + typeName + "'.");
0949: }
0950: return toImport;
0951: } catch (TypeException e) {
0952: log
0953: .error(
0954: "createType() - adapter writeType failed in type creation ",
0955: e);
0956: throw new TypeException(
0957: ContelligentExceptionID.type_persistence, e);
0958: } catch (Exception e) {
0959: log.error("createType() - Exception: ", e);
0960: throw new TypeException(
0961: ContelligentExceptionID.type_generic, e);
0962: }
0963: }
0964:
0965: public void invalidateTypes() {
0966: initTypes();
0967: }
0968:
0969: private TypeImpl createTypeImpl(TypeElement typeDefinition)
0970: throws Exception {
0971: String typeName = typeDefinition.getName();
0972: String super TypeName = null;
0973: String typeClassName = null;
0974: if (typeDefinition.getExtendType() != null) {
0975: super TypeName = typeDefinition.getExtendType();
0976: typeClassName = typeDefinition.getExtendClassImpl();
0977: } else if (typeDefinition.getRestrictType() != null) {
0978: super TypeName = typeDefinition.getRestrictType();
0979: } else {
0980: typeClassName = typeDefinition.getClassImpl();
0981: }
0982:
0983: Map typePropertyMap = new HashMap(); // a map containing
0984: // (String/TypeProperty) pairs
0985: Iterator it = typeDefinition.getPropertyElementList()
0986: .iterator();
0987: while (it.hasNext()) {
0988: TypePropertyElement tpElement = (TypePropertyElement) it
0989: .next();
0990: TypeProperty typeProperty = propertyHandler
0991: .createTypeProperty(tpElement);
0992: typeProperty.setDefiningTypeName(typeName);
0993: typePropertyMap.put(typeProperty.getName(), typeProperty);
0994: }
0995: boolean restrictsOnly = (super TypeName != null && typeClassName == null);
0996: ComponentPath blueprintPath = (typeDefinition
0997: .getBlueprintPath() != null ? new ComponentPath(
0998: typeDefinition.getBlueprintPath()) : null);
0999: return new TypeImpl(-1, typeName, typeDefinition.getGroup(),
1000: super TypeName, typeDefinition.getMetainfoElement(),
1001: typePropertyMap, null, typeClassName, restrictsOnly,
1002: blueprintPath);
1003: }
1004:
1005: private void storeModification(String typeName, TypeImpl type,
1006: boolean deferInit) throws TypeException {
1007: Map map = (Map) effectiveTypeMap.get();
1008: if (map == null) {
1009: map = new HashMap(typeMap.size());
1010: map.putAll(typeMap);
1011: effectiveTypeMap.set(map);
1012: }
1013:
1014: if (map.containsKey(typeName)) {
1015: if (log.isDebugEnabled()) {
1016: log
1017: .debug("storeModification() - type '"
1018: + typeName
1019: + "' already exists => overwriting it and recalculating property maps of dependend types afterwards ...");
1020: }
1021: if (type == null) {
1022: map.remove(typeName);
1023: } else {
1024: map.put(typeName, type);
1025: }
1026: Map newBlueprintMap = blueprintMap;
1027: if (!deferInit) {
1028: newBlueprintMap = initAllTypes(map);
1029: }
1030: effectiveBlueprintMap.set(newBlueprintMap);
1031: } else {
1032: if (log.isDebugEnabled()) {
1033: log
1034: .debug("storeModification() - adding new type type '"
1035: + typeName
1036: + "', no need to recalculate all property maps ...");
1037: }
1038: map.put(typeName, type);
1039: initType(type, map, true); // true: check type-properties for
1040: // incompatible overwrites
1041: if (type.isBlueprint()) {
1042: Map blueprMap = (Map) effectiveBlueprintMap.get();
1043: if (blueprMap == null) {
1044: blueprMap = new HashMap(blueprintMap.size());
1045: blueprMap.putAll(blueprintMap);
1046: effectiveBlueprintMap.set(blueprMap);
1047: }
1048: blueprMap.put(type.getBlueprintPath(), type);
1049: }
1050: }
1051: }
1052:
1053: private Map getTypeMap() {
1054: Map map = (Map) effectiveTypeMap.get();
1055: return (map != null ? map : typeMap);
1056: }
1057:
1058: private Map getBlueprintMap() {
1059: Map map = (Map) effectiveBlueprintMap.get();
1060: return (map != null ? map : blueprintMap);
1061: }
1062:
1063: private Set getAddedTypes(boolean create) {
1064: Set answer = (Set) addedTypes.get();
1065:
1066: if (answer == null && create) {
1067: answer = new HashSet();
1068: addedTypes.set(answer);
1069: }
1070: return answer;
1071: }
1072:
1073: private Set getRemovedTypes(boolean create) {
1074: Set answer = (Set) removedTypes.get();
1075:
1076: if (answer == null && create) {
1077: answer = new HashSet();
1078: removedTypes.set(answer);
1079: }
1080: return answer;
1081: }
1082:
1083: synchronized List getTypesFromPackage(String name) {
1084: List types = new ArrayList();
1085: Iterator entries = getTypeMap().entrySet().iterator();
1086: while (entries.hasNext()) {
1087: Map.Entry entry = (Map.Entry) entries.next();
1088: if (((String) entry.getKey()).startsWith(name + ".")) {
1089: types.add(entry.getValue());
1090: }
1091: }
1092: // sort according to the type hierarchy:
1093: List list = sortTypes(types);
1094: Collections.reverse(list);
1095: return list;
1096: }
1097:
1098: void setDeferInit(boolean defer) {
1099: if (defer) {
1100: deferInit.set(new Boolean(defer));
1101: } else {
1102: deferInit.set(null);
1103: }
1104: }
1105:
1106: private boolean isDeferInit() {
1107: Boolean value = (Boolean) deferInit.get();
1108:
1109: if (value == null) {
1110: return false;
1111: } else {
1112: return value.booleanValue();
1113: }
1114: }
1115: }
|