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.InputStream;
0022: import java.io.Writer;
0023: import java.math.BigDecimal;
0024: import java.util.ArrayList;
0025: import java.util.Collection;
0026: import java.util.Collections;
0027: import java.util.HashMap;
0028: import java.util.HashSet;
0029: import java.util.Iterator;
0030: import java.util.LinkedList;
0031: import java.util.List;
0032: import java.util.ListIterator;
0033: import java.util.Map;
0034: import java.util.Set;
0035:
0036: import javax.transaction.Status;
0037:
0038: import org.apache.commons.fileupload.FileItem;
0039:
0040: import de.finix.contelligent.CallData;
0041: import de.finix.contelligent.Component;
0042: import de.finix.contelligent.ComponentContext;
0043: import de.finix.contelligent.ComponentCreationException;
0044: import de.finix.contelligent.ComponentLink;
0045: import de.finix.contelligent.ComponentManager;
0046: import de.finix.contelligent.ComponentNotFoundException;
0047: import de.finix.contelligent.ComponentPath;
0048: import de.finix.contelligent.ComponentPathException;
0049: import de.finix.contelligent.Container;
0050: import de.finix.contelligent.Contelligent;
0051: import de.finix.contelligent.CopyMode;
0052: import de.finix.contelligent.GlobalComponentPath;
0053: import de.finix.contelligent.ModificationVetoException;
0054: import de.finix.contelligent.ObservingContainer;
0055: import de.finix.contelligent.SecureComponent;
0056: import de.finix.contelligent.Type;
0057: import de.finix.contelligent.category.Category;
0058: import de.finix.contelligent.category.CategoryException;
0059: import de.finix.contelligent.category.CategoryManager;
0060: import de.finix.contelligent.category.CategorySubset;
0061: import de.finix.contelligent.components.Folder;
0062: import de.finix.contelligent.components.SortedFolder;
0063: import de.finix.contelligent.components.legacy.FileFacade;
0064: import de.finix.contelligent.content.Metadata;
0065: import de.finix.contelligent.core.security.AccessControlList;
0066: import de.finix.contelligent.core.security.AclEntry;
0067: import de.finix.contelligent.core.security.ComponentAccess;
0068: import de.finix.contelligent.core.security.ComponentPermission;
0069: import de.finix.contelligent.core.security.ContelligentPrincipal;
0070: import de.finix.contelligent.core.security.ContelligentPrincipalFactory;
0071: import de.finix.contelligent.core.security.ContelligentSecurityManager;
0072: import de.finix.contelligent.core.security.User;
0073: import de.finix.contelligent.event.ComponentEvent;
0074: import de.finix.contelligent.event.ContelligentEvent;
0075: import de.finix.contelligent.event.EventQueue;
0076: import de.finix.contelligent.event.TypeEvent;
0077: import de.finix.contelligent.exception.ComponentAlreadyExistsException;
0078: import de.finix.contelligent.exception.ComponentAlreadyLockedException;
0079: import de.finix.contelligent.exception.ComponentLockException;
0080: import de.finix.contelligent.exception.ComponentMoveException;
0081: import de.finix.contelligent.exception.ComponentPersistenceException;
0082: import de.finix.contelligent.exception.ComponentSystemException;
0083: import de.finix.contelligent.exception.ComponentWriteException;
0084: import de.finix.contelligent.exception.ContelligentException;
0085: import de.finix.contelligent.exception.ContelligentExceptionID;
0086: import de.finix.contelligent.exception.ContelligentRuntimeException;
0087: import de.finix.contelligent.exception.ContelligentSecurityException;
0088: import de.finix.contelligent.exception.MissingPermissionException;
0089: import de.finix.contelligent.exception.NoDeletePermissionException;
0090: import de.finix.contelligent.exception.NoReadPermissionException;
0091: import de.finix.contelligent.exception.NoWritePermissionException;
0092: import de.finix.contelligent.exception.NotLockOwnerException;
0093: import de.finix.contelligent.exception.NotOwnerException;
0094: import de.finix.contelligent.exception.RelationExistsException;
0095: import de.finix.contelligent.exception.RelationsException;
0096: import de.finix.contelligent.exception.TypeException;
0097: import de.finix.contelligent.exception.UnknownTypeException;
0098: import de.finix.contelligent.exception.WouldCreateDeadRelationsException;
0099: import de.finix.contelligent.logging.LoggingService;
0100: import de.finix.contelligent.persistence.ComponentDBAdapter;
0101: import de.finix.contelligent.persistence.ComponentDBPathHolder;
0102: import de.finix.contelligent.persistence.ComponentPersistenceAdapter;
0103: import de.finix.contelligent.persistence.LocalFileAdapter;
0104: import de.finix.contelligent.resource.BinaryResource;
0105: import de.finix.contelligent.resource.NumberResource;
0106: import de.finix.contelligent.resource.Resource;
0107: import de.finix.contelligent.resource.StringResource;
0108: import de.finix.contelligent.resource.TextResource;
0109: import de.finix.contelligent.search.system.SystemIndex;
0110: import de.finix.contelligent.search.system.SystemIndexer;
0111: import de.finix.contelligent.util.StringHash;
0112: import de.finix.contelligent.util.ThreadedMem;
0113: import de.finix.contelligent.xml.elements.ACLElement;
0114: import de.finix.contelligent.xml.elements.ComponentElement;
0115: import de.finix.contelligent.xml.elements.ComponentMetainfoElement;
0116: import de.finix.contelligent.xml.elements.ComponentSecurityElement;
0117: import de.finix.contelligent.xml.elements.PrincipalElement;
0118: import de.finix.contelligent.xml.elements.ResourceElement;
0119: import de.finix.contelligent.xml.elements.SecurityElement;
0120: import de.finix.contelligent.xml.elements.TypeElement;
0121:
0122: /**
0123: * A <code>BasicComponentManager</code> is a {@link ComponentManager} which
0124: * directly operates on the underlying persistent store.
0125: *
0126: * Since accessing the database for every component access is very slow, a
0127: * production environment should always use a cacheing subclass of this,
0128: * although this class can be used directly for development purposes.
0129: */
0130: public class BasicComponentManager implements ComponentManagerInternal {
0131: final static org.apache.log4j.Logger log = LoggingService
0132: .getLogger(BasicComponentManager.class);
0133:
0134: /**
0135: * This type is used for all links, for example if a final component should
0136: * be copied.
0137: */
0138: public static final String DEFAULT_LINK_TYPE = "contelligent.core.Link";
0139:
0140: /** This property must be passed in the map when creating a link. */
0141: public static final String DEFAULT_LINK_TYPE_PATH_PROPERTY = "targetPath";
0142:
0143: /**
0144: * Basic certification level using low-security but less cpu intensive
0145: * operations only.
0146: */
0147: public static final int CERT_BASIC = 1;
0148:
0149: /**
0150: * Extended certification level for higher security requirements (reserved;
0151: * not supported yet)
0152: */
0153: public static final int CERT_SIGNED = 2;
0154:
0155: /**
0156: * Only certified as safe for execution by user name.
0157: */
0158: public static final int CERT_USER = 3;
0159:
0160: // if true no relations are checked in beforeCompletion():
0161: final static boolean SKIP_RELATIONS_CHECK = true;
0162:
0163: final Container rootContainer;
0164:
0165: final BasicComponentManager parent;
0166:
0167: final String name;
0168:
0169: final AccessControlList rootACL;
0170:
0171: final public String ROOT_TYPENAME = DEFAULT_FOLDER_TYPE;
0172:
0173: final public String ROOT_TYPEGROUP = "container";
0174:
0175: final ComponentFactoryImpl componentFactory;
0176:
0177: final LocalFileAdapter fileAdapter;
0178:
0179: final ComponentPersistenceAdapter componentAdapter;
0180:
0181: final User defaultOwner;
0182:
0183: final Contelligent contelligent;
0184:
0185: final ComponentLockManager componentLockManager;
0186:
0187: final RelationsManagerImpl relationsManager;
0188:
0189: private SystemIndex systemIndex;
0190:
0191: private SystemIndexer listener;
0192:
0193: private Set readOnlyPaths = new HashSet(0);
0194:
0195: /** contains a Map with (ComponentPath, Component) entries */
0196: final private ThreadLocal cloneMap = new ThreadLocal();
0197:
0198: /** contains a List with ContelligentEvent instances */
0199: final private ThreadLocal eventList = new ThreadLocal();
0200:
0201: /**
0202: * contains a List of String instances, the names of files to move to parent
0203: * file-adapter
0204: */
0205: final private ThreadLocal filesToMoveList = new ThreadLocal();
0206:
0207: /**
0208: * a Boolean flag indicating that this manager was destroyed and
0209: * file-adapters should be destroyed too
0210: */
0211: final private ThreadLocal destroyFileAdapters = new ThreadLocal();
0212:
0213: /**
0214: * a boolean flag indicating that this managers parent manager was used in
0215: * the current transaction
0216: */
0217: final private ThreadLocal parentInTransaction = new ThreadLocal();
0218:
0219: private AccessControlList acl;
0220:
0221: final private boolean isImportManager;
0222:
0223: // system property to disable check for dead relations in
0224: // commitServer/commitSubtree
0225: static final String PROPERTY_DISABLE_DEADRELATIONSCHECK = "contelligent.unsupported.disable.checkdeadrelations";
0226:
0227: static final boolean deadRelationsCheckDisabled = Boolean
0228: .getBoolean(PROPERTY_DISABLE_DEADRELATIONSCHECK);
0229:
0230: /**
0231: * Creates a new <code>BasicComponentManager</code> instance and
0232: * initializes all adapters.
0233: *
0234: * @exception ContelligentException
0235: * if an error occurs
0236: */
0237: BasicComponentManager(String fullName,
0238: BasicComponentManager parent, Contelligent contelligent,
0239: ComponentLockManager componentLockManager,
0240: SecurityElement securityConfig,
0241: ComponentFactory componentFactory,
0242: ComponentPersistenceAdapter componentAdapter,
0243: LocalFileAdapter fileAdapter, AccessControlList acl,
0244: Map properties) throws ContelligentException {
0245: this .name = fullName;
0246: this .parent = parent;
0247: this .contelligent = contelligent;
0248: this .componentLockManager = componentLockManager;
0249: this .componentAdapter = componentAdapter;
0250: this .isImportManager = (properties == null) ? false : Boolean
0251: .valueOf((String) properties.get(PROPERTY_ISIMPORT))
0252: .booleanValue();
0253: this .relationsManager = (RelationsManagerImpl) contelligent
0254: .getRelationsManager();
0255:
0256: try {
0257: this .componentFactory = (ComponentFactoryImpl) componentFactory;
0258: this .fileAdapter = fileAdapter;
0259:
0260: if (securityConfig != null) {
0261: PrincipalElement defaultOwnerElement = securityConfig
0262: .getDefaultOwnerElement();
0263: log.info("'" + this .name
0264: + "':<init> - ... set default owner user to '"
0265: + defaultOwnerElement.getGroupId() + ':'
0266: + defaultOwnerElement.getPrincipalId()
0267: + "' ...");
0268: if (ContelligentSecurityManager.getInstance()
0269: .existsUser(
0270: defaultOwnerElement.getPrincipalId(),
0271: defaultOwnerElement.getGroupId())) {
0272: defaultOwner = ContelligentPrincipalFactory
0273: .createUserPrincipal(defaultOwnerElement
0274: .getPrincipalId(),
0275: defaultOwnerElement.getGroupId());
0276: } else {
0277: log
0278: .warn("'"
0279: + this .name
0280: + "']:<init> - ... could not find default-owner (groupId='"
0281: + defaultOwnerElement.getGroupId()
0282: + "', id='"
0283: + defaultOwnerElement
0284: .getPrincipalId()
0285: + "') -> using SYSTEM instead.");
0286: defaultOwner = getSystemUser();
0287: }
0288: rootACL = createRootACL(securityConfig.getACLElement());
0289: log.info("'" + this .name
0290: + "':<init> - ... done with security-config.");
0291: } else {
0292: if (parent == null) {
0293: log
0294: .fatal("'"
0295: + this .name
0296: + "':<init> - need a security-config to configure without a parent!");
0297: throw new ContelligentException(
0298: "'"
0299: + this .name
0300: + "':<init> - need a security-config to configure without a parent!");
0301: }
0302: defaultOwner = parent.defaultOwner;
0303: rootACL = (AccessControlList) parent.rootACL.clone();
0304: }
0305: rootContainer = createRootContainer();
0306: this .acl = acl;
0307:
0308: if (!isImportManager && contelligent.hasSystemIndex()) {
0309: systemIndex = new SystemIndex(this );
0310: listener = new SystemIndexer(systemIndex);
0311: EventQueue.getInstance().addListener(listener);
0312: }
0313: log.debug("'" + this .name + "':<init> - done.");
0314: } catch (ComponentPersistenceException e) {
0315: log
0316: .error(
0317: "'"
0318: + this .name
0319: + "':<init> - exception during initialization of adapter: ",
0320: e);
0321: throw new ContelligentException(
0322: this
0323: + ":<init> - exception during initialization of adapter.",
0324: e);
0325: } catch (Exception e) {
0326: log
0327: .error(
0328: "'"
0329: + this .name
0330: + "':<init> - Exception during initialization of adapter: ",
0331: e);
0332: throw new ContelligentException(
0333: this
0334: + ":<init> - exception during initialization of adapter.",
0335: e);
0336: }
0337: }
0338:
0339: /**
0340: * Answer true whether this is the root manager.
0341: */
0342: final public boolean isRoot() {
0343: return parent == null;
0344: }
0345:
0346: /**
0347: * Answer true whether this is an import manager.
0348: *
0349: * @return
0350: */
0351: final public boolean isImport() {
0352: return isImportManager;
0353: }
0354:
0355: final public ComponentManager getParent() {
0356: return parent;
0357: }
0358:
0359: final public ComponentPersistenceAdapter getComponentPersistenceAdapter() {
0360: return componentAdapter;
0361: }
0362:
0363: void destroy(boolean includeFileAdapters)
0364: throws ContelligentException {
0365: if (systemIndex != null) {
0366: EventQueue.getInstance().removeListener(listener);
0367: listener.stopThread();
0368: systemIndex.destroy();
0369: systemIndex = null;
0370: listener = null;
0371: }
0372:
0373: if (isRoot()) {
0374: throw new ContelligentException(
0375: "Cannot destroy root manager");
0376: }
0377: // XXX: maybe check/destroy all sessions related to this manager first.
0378: // (rs)
0379: log.debug("'" + name + "':destroy() - begin ...");
0380: componentAdapter.destroy();
0381: if (includeFileAdapters) {
0382: // thread-local flag: we can't simply destroy the file-adapter here
0383: // because that is not transactional!
0384: destroyFileAdapters.set(Boolean.TRUE);
0385: }
0386: componentLockManager.removeLocksForComponentManager(this );
0387: relationsManager.removeRelationsOfTree(ComponentPath.ROOT_PATH,
0388: this .getId());
0389: invalidatePath(ComponentPath.ROOT_PATH, true);
0390: log.debug("'" + name + "':destroy() - ... done.");
0391: }
0392:
0393: /**
0394: * Implementation of
0395: * {@link de.finix.contelligent.ComponentManager#commitServer}.
0396: */
0397: final public void commitServer(CallData callData)
0398: throws ContelligentException, ModificationVetoException,
0399: RelationsException, ComponentLockException {
0400: commitPath(ComponentPath.ROOT_PATH, callData);
0401: parent.checkRelations(callData);
0402: }
0403:
0404: /**
0405: * Implementation of {@link ComponentManager#commitSubtree}.
0406: */
0407: final public void commitSubtree(ComponentPath root,
0408: CallData callData) throws ContelligentException,
0409: ModificationVetoException, RelationsException,
0410: ComponentLockException {
0411: commitPath(root, callData);
0412: parent.checkRelations(callData);
0413: }
0414:
0415: final private void commitPath(ComponentPath rootPath,
0416: CallData callData) throws ContelligentException,
0417: ModificationVetoException, RelationsException,
0418: ComponentLockException {
0419: boolean debugEnabled = log.isDebugEnabled();
0420: // FIXME: check if user has permission COMMIT_SUBTREE
0421: if (isRoot()) {
0422: throw new RuntimeException("Operation not supported");
0423: }
0424: // Make sure the parent container already exists in the parent manager
0425: if (!rootPath.isRoot()) {
0426: ComponentPath parentPath = rootPath.parentPath();
0427: if (!parent.componentExists(parentPath)) {
0428: throw new ComponentNotFoundException(
0429: ContelligentExceptionID.component_notFoundInParentCM,
0430: parentPath);
0431: }
0432: if (componentExists(parentPath, false)) {
0433: Component parentComp = getComponent(parentPath,
0434: callData);
0435: // If a sorted folder and its subcomponent are modified,
0436: // only committing the subcomponent can result in an
0437: // inconsistent state on the sorted folder, so we
0438: // prevent this.
0439: if (parentComp instanceof SortedFolder) {
0440: throw new ComponentPersistenceException(
0441: ContelligentExceptionID.component_commit_without_sorted_parent);
0442: }
0443: }
0444: }
0445: // If a component is deleted and recreated, you cannot just commit
0446: // one of its subcomponents, since otherwise you could create an
0447: // inconsistent state that way.
0448: if (isSubpathOfDeletedOrRecreated(rootPath, callData)) {
0449: throw new ComponentPersistenceException(
0450: ContelligentExceptionID.component_recreated_parent);
0451: }
0452:
0453: // XXX: if one has the permission we must not check locks so the admin
0454: // may commit changes from various users
0455: Iterator i = componentAdapter.getLocalComponentNames(rootPath)
0456: .iterator();
0457: while (i.hasNext()) {
0458: ComponentDBPathHolder dbPath = (ComponentDBPathHolder) i
0459: .next();
0460: ComponentPath path = dbPath.getPath();
0461: if (dbPath.isRemoved()) {
0462: parent.deleteComponentTree(path, callData, true, false,
0463: false, true); // fires delete event
0464: if (debugEnabled)
0465: log.debug("'" + this .name
0466: + "':commitPath() - ... deleted tree '"
0467: + path + "' in parent ...");
0468: // removes relations but don't checks for remaining relations!
0469: } else {
0470: try {
0471: Component clonedComponent = cloneForManager(path,
0472: parent, callData);
0473: parent.addClone(path, clonedComponent);
0474: if (debugEnabled)
0475: log.debug("'" + this .name
0476: + "':commitPath() - added clone of '"
0477: + path + "' to parent '" + parent
0478: + "' ...");
0479: if (dbPath.isRecreated()) {
0480: parent.deleteComponentTree(path, callData,
0481: true, false, false, true); // fires delete event
0482: // removes relations but don't checks for remaining relations!
0483: parent.addEvent(new ComponentEvent(
0484: ComponentEvent.ADD, clonedComponent,
0485: parent.getName()));
0486: } else {
0487: if (parent.componentExists(path)) {
0488: parent.getComponentPersistenceAdapter()
0489: .delete(path, false, false);
0490: relationsManager.removeRelations(path,
0491: parent.getId());
0492: parent.addEvent(new ComponentEvent(
0493: ComponentEvent.CHANGE,
0494: clonedComponent, parent.getName()));
0495: } else {
0496: parent.addEvent(new ComponentEvent(
0497: ComponentEvent.ADD,
0498: clonedComponent, parent.getName()));
0499: }
0500: }
0501: } catch (Exception e) { // should never occur since we clone an already existing type !!
0502: log
0503: .error("'"
0504: + this .name
0505: + "':commitPath() - Exception while cloning '"
0506: + path + "': " + e);
0507: throw new ComponentPersistenceException(
0508: new Object[] { path.toPath() }, e);
0509: }
0510: }
0511: }
0512:
0513: checkForFilesToMove(rootPath, callData);
0514: relationsManager.moveRelationsOfTree(rootPath, this .getId(),
0515: parent.getId(), true);
0516:
0517: if (ComponentPath.ROOT_PATH.equals(rootPath)) {
0518: parent.getComponentPersistenceAdapter().mergeAdapter(
0519: this .componentAdapter);
0520: componentLockManager.removeLocksForComponentManager(this );
0521: } else {
0522: parent.getComponentPersistenceAdapter()
0523: .mergeSubtreeOfAdapter(rootPath,
0524: this .componentAdapter);
0525: componentLockManager.removeLocksForComponentTree(rootPath);
0526: }
0527:
0528: parentInTransaction.set(Boolean.TRUE);
0529: invalidatePath(rootPath, true);
0530: }
0531:
0532: final public void checkRelations(CallData callData)
0533: throws ComponentPersistenceException,
0534: WouldCreateDeadRelationsException {
0535: checkRelationsOfComponent(ComponentPath.ROOT_PATH, true,
0536: callData);
0537: }
0538:
0539: final private void checkRelationsOfComponent(ComponentPath path,
0540: boolean recursive, CallData callData)
0541: throws ComponentPersistenceException,
0542: WouldCreateDeadRelationsException {
0543: if (!callData.shouldCheckRelations()) {
0544: log
0545: .debug("'"
0546: + this .name
0547: + "':checkRelations() - check for dead relations disabled in callData!");
0548: return;
0549: }
0550: if (deadRelationsCheckDisabled) {
0551: log
0552: .warn("'"
0553: + this .name
0554: + "':checkRelations() - check for dead relations disabled!");
0555: return;
0556: }
0557: log
0558: .debug("'"
0559: + this .name
0560: + "':checkRelations() - ... now checking for dead relations in subtree '"
0561: + path + "' ...");
0562: Map deadRelations = relationsManager.getDeadRelations(path,
0563: this .getIdsUpToRoot(), recursive);
0564: if (!deadRelations.isEmpty()) {
0565: log.debug("'" + name
0566: + "':checkRelations() - found dead relations: "
0567: + deadRelations + "!");
0568: callData.markForRollback();
0569: throw new WouldCreateDeadRelationsException(path,
0570: deadRelations);
0571: }
0572: }
0573:
0574: /**
0575: * Force a relation check (to be used by
0576: * {@link AbstractCallDataImpl#doWithoutRelationsCheck} only).
0577: *
0578: * @throws ComponentPersistenceException
0579: * @throws WouldCreateDeadRelationsException
0580: */
0581: final void checkRelations() throws ComponentPersistenceException,
0582: WouldCreateDeadRelationsException {
0583: Map deadRelations = relationsManager.getDeadRelations(
0584: ComponentPath.ROOT_PATH, this .getIdsUpToRoot(), true);
0585: if (!deadRelations.isEmpty()) {
0586: log.debug("'" + name
0587: + "':checkRelations() - found dead relations: "
0588: + deadRelations + "!");
0589: throw new WouldCreateDeadRelationsException(
0590: ComponentPath.ROOT_PATH, deadRelations);
0591: }
0592: }
0593:
0594: private Component cloneForManager(ComponentPath componentPath,
0595: ComponentManagerInternal manager, CallData callData)
0596: throws Exception {
0597: Component component = this .getComponent(componentPath,
0598: callData, false);
0599: ComponentContextImpl orgCtx = (ComponentContextImpl) component
0600: .getComponentContext();
0601: ComponentContextImpl clonedCtx = orgCtx.clone(parent);
0602: Type type = orgCtx.getType();
0603: Component clonedComponent = componentFactory
0604: .createRawInstance(type); // throws
0605: // TypeException
0606: type.setProperties(clonedComponent, type.getProperties(
0607: component, false));
0608: clonedCtx.setComponent(clonedComponent);
0609: clonedComponent.postCreate();
0610: return clonedComponent;
0611: }
0612:
0613: /**
0614: * Searches all components with a path beneath <tt>rootPath</tt> which
0615: * have a type equal to {@link FileFacade#TYPENAME} or a subtype of this
0616: * type and adds all corresponding file-names to {@link #filesToMoveList}.
0617: * These files get then moved into the parent managers adapter in
0618: * {@link #afterCompletion} if the transaction was successfully commited.
0619: *
0620: * @param rootPath
0621: * the path to start searching FileFacade instances, pass null
0622: * for root path.
0623: * @param callData
0624: * a <code>CallData</code> value
0625: * @exception ComponentPersistenceException
0626: * if an error occurs
0627: */
0628: final private void checkForFilesToMove(ComponentPath rootPath,
0629: CallData callData) throws ComponentPersistenceException {
0630: // we want only files from this manager!
0631: long[] ids = new long[] { this .getId() };
0632: Set typeNames = componentFactory
0633: .getSubTypeNames(FileFacade.TYPENAME);
0634: typeNames.add(FileFacade.TYPENAME);
0635: Set filePaths = componentAdapter
0636: .getComponentPathsForTypeInstances(rootPath, typeNames,
0637: ids);
0638: log.debug("'" + name + "':checkFilesToMove() - found "
0639: + filePaths.size() + " files to move ...");
0640: if (filePaths.size() > 0) {
0641: List fileNameList = (List) filesToMoveList.get();
0642: if (fileNameList == null) {
0643: fileNameList = new LinkedList();
0644: filesToMoveList.set(fileNameList);
0645: }
0646: Iterator files = filePaths.iterator();
0647: while (files.hasNext()) {
0648: ComponentPath path = (ComponentPath) files.next();
0649: try {
0650: FileFacade fileFacade = (FileFacade) getComponent(
0651: path, callData);
0652: String resourceName = fileFacade.getResourceName();
0653: fileNameList.add(resourceName);
0654: } catch (Exception e) {
0655: log
0656: .error("'"
0657: + name
0658: + "':checkFilesToMove() - Exception while fetching resource-name from external file component '"
0659: + path
0660: + "' (ignoring this component): "
0661: + e);
0662: }
0663: }
0664: }
0665: }
0666:
0667: protected boolean isSubpathOfDeletedOrRecreated(ComponentPath path,
0668: CallData callData) throws ComponentPersistenceException {
0669: ComponentPath parent = path.parentPath();
0670: if (parent == null) { // Happens if we call parentPath on the root
0671: // path
0672: return false;
0673: }
0674: return (componentAdapter.recreatedHierarchical(parent) || componentAdapter
0675: .deletedHierarchical(parent));
0676: }
0677:
0678: /**
0679: * Rollback all changes in the given subtree.
0680: *
0681: * @param root
0682: * @param callData
0683: * @throws ComponentPersistenceException
0684: */
0685: final public void rollbackChangesInSubtree(ComponentPath root,
0686: CallData callData) throws ComponentPersistenceException,
0687: NotLockOwnerException {
0688: boolean wasDeleted = componentAdapter.deleted(root);
0689: if (isSubpathOfDeletedOrRecreated(root, callData)) {
0690: throw new ComponentPersistenceException(
0691: ContelligentExceptionID.component_recreated_parent);
0692: }
0693: componentLockManager.checkLockPermission(root, callData);
0694: componentAdapter.removeChanges(root);
0695: componentLockManager.removeLocksForComponentTree(root);
0696: // FIXME: add changed components or use 'invalidate-event' !
0697: EventQueue.getInstance().addEvent(
0698: new ComponentEvent(ComponentEvent.CHANGE, root,
0699: this .name));
0700: invalidatePath(root, true);
0701: if (wasDeleted) {
0702: // Make sure a SortedFolder above our tree fixes its sort order
0703: try {
0704: Component added = getComponent(root, callData);
0705: Container parent = parentContainer(added);
0706: fireAddEvent(parent, added);
0707: } catch (ComponentNotFoundException cne) {
0708: throw new ComponentPersistenceException(cne);
0709: } catch (ModificationVetoException mve) {
0710: throw new ComponentPersistenceException(mve);
0711: }
0712: }
0713: }
0714:
0715: final public LocalFileAdapter getFileAdapter() {
0716: return this .fileAdapter;
0717: }
0718:
0719: final public String getName() {
0720: return name;
0721: }
0722:
0723: final public Container getRootComponent() {
0724: return rootContainer;
0725: }
0726:
0727: /**
0728: * Implementation of {@link ComponentManager#parentContainer}. <BR>
0729: * If this implementation doesn't find the parent a
0730: * <code>ContelligentRuntimeException</code> is thrown to indicate this
0731: * fatal error as every component except the root container must have a
0732: * parent.
0733: */
0734: final public Container parentContainer(Component component) {
0735: try {
0736: ComponentPath path = component.getComponentContext()
0737: .getPath();
0738: if (isRootPath(path))
0739: return null;
0740: return (Container) getComponent(path.parentPath(),
0741: ThreadedMem.getCallData());
0742: } catch (ComponentNotFoundException e) {
0743: log
0744: .fatal("'"
0745: + this .name
0746: + "':parentContainer() - can't find parent of component '"
0747: + component + "': " + e);
0748: throw new ContelligentRuntimeException(
0749: "'"
0750: + this .name
0751: + "':parentContainer() - can't find parent of component '"
0752: + component + "'!", e);
0753: }
0754: }
0755:
0756: /**
0757: * Implementation of
0758: * {@link ComponentManager#getComponent(ComponentPath, CallData)}.
0759: */
0760: final public Component getComponent(ComponentPath path,
0761: CallData callData) throws ComponentNotFoundException,
0762: ComponentCreationException {
0763: return retrieveComponent(path, null, callData, true);
0764: }
0765:
0766: /**
0767: * Implementation of
0768: * {@link ComponentManager#getComponent(ComponentPath, CallData, boolean)}.
0769: */
0770: final public Component getComponent(ComponentPath path,
0771: CallData callData, boolean followLinks)
0772: throws ComponentNotFoundException,
0773: ComponentCreationException {
0774: return retrieveComponent(path, null, callData, followLinks);
0775: }
0776:
0777: final public Component getSubcomponent(Container parentContainer,
0778: String subName, CallData callData)
0779: throws ComponentNotFoundException, ComponentPathException,
0780: ComponentCreationException {
0781: return retrieveComponent(new ComponentPath(subName),
0782: parentContainer, callData, true);
0783: }
0784:
0785: final public Component getSubcomponent(Container parentContainer,
0786: String relativePath, CallData callData, boolean followLinks)
0787: throws ComponentNotFoundException, ComponentPathException,
0788: ComponentCreationException {
0789: return retrieveComponent(new ComponentPath(relativePath),
0790: parentContainer, callData, followLinks);
0791: }
0792:
0793: final public Component getSubcomponent(Container parentContainer,
0794: ComponentPath relativePath, CallData callData)
0795: throws ComponentNotFoundException,
0796: ComponentCreationException {
0797: return retrieveComponent(relativePath, parentContainer,
0798: callData, true);
0799: }
0800:
0801: final public Component getSubcomponent(Container parentContainer,
0802: ComponentPath relativePath, CallData callData,
0803: boolean followLinks) throws ComponentNotFoundException,
0804: ComponentCreationException {
0805: return retrieveComponent(relativePath, parentContainer,
0806: callData, followLinks);
0807: }
0808:
0809: /**
0810: * Returns the {@link Component} associated with the given
0811: * {@link ComponentPath path} if it exists in this manager or in any parent
0812: * manager or otherwise throws a <code>ComponentNotFoundException</code>.
0813: * The <tt>path</tt> may be {@link ComponentPath#isAbsolute absolute} or
0814: * {@link ComponentPath#isRelative relative} but in the latter case
0815: * parameter <tt>parentContainer</tt> must not be null. <BR>
0816: * If the path {@link CategoryManager#containsCategory contains categories}
0817: * the category-tokens get replaced using the category map found in the
0818: * given calldata instance. Note that this may result in a significant
0819: * performance loss because for every category-token found we have to call
0820: * {@link #componentExists} maybe multiple times. Hereby the number of calls
0821: * depends on the number of fallbacks the category defines and which of
0822: * those values does actually exist. <BR>
0823: * The lookup of any component should be performed in the following order:
0824: * <OL>
0825: * <LI>if the {@link #getClone clone-map} contains an entry for this path
0826: * return it. Note that any clone gets stored using its absolute path as
0827: * key.
0828: * <LI>if the component exists within this manager return it either from
0829: * cache or {@link #loadRawComponent load} it from the database. If the
0830: * component gets loaded {@link Component#postCreate} have to be called.
0831: * <LI>else ask the parent manager to retrieve the component
0832: * </OL>
0833: * If the component was loaded or found in a cache and parameter
0834: * <tt>followLinks</tt> is true and the component is an instance of
0835: * {@link ComponentLink} the target of the link must be returned instead of
0836: * the component.
0837: *
0838: * @param path
0839: * the path of the component to return, may be relative or
0840: * absolute
0841: * @param parentContainer
0842: * the parent container of the component to return, is only
0843: * necessary of path is relative.
0844: * @param callData
0845: * CallData instance of this call
0846: * @param followLinks
0847: * if true return target of {@link ComponentLink links} instead
0848: * of link itself.
0849: * @exception ComponentNotFoundException
0850: * if the component does not exist in this manager nor in any
0851: * parent manager.
0852: * @exception ComponentCreationException
0853: * if anything goes wrong during initialization of the
0854: * component, for example if {@link Component#postCreate}
0855: * throws an exception.
0856: * @see LRUMapComponentManager for an implementation using a cache.
0857: */
0858: Component retrieveComponent(ComponentPath path,
0859: Container parentContainer, CallData callData,
0860: boolean followLinks) throws ComponentNotFoundException,
0861: ComponentCreationException {
0862: final boolean debugEnabled = log.isDebugEnabled();
0863: Component component = null;
0864:
0865: // First check if there is a clone for the requested component
0866: if (path.isAbsolute()) {
0867: if (isRootPath(path)) {
0868: return getRootComponent();
0869: }
0870: component = getClone(path);
0871: } else {
0872: if (parentContainer == null) {
0873: throw new ComponentNotFoundException(
0874: ContelligentExceptionID.component_notFound_relativePathWithoutParent,
0875: path);
0876: }
0877: final ComponentContextImpl parentCtx = (ComponentContextImpl) parentContainer
0878: .getComponentContext();
0879: path = parentCtx.getPath().append(path);
0880: component = getClone(path);
0881: }
0882:
0883: if (component != null) {
0884: // A removed clone means that there is nothing to see here for
0885: // this transaction
0886: if (component.getComponentContext().isRemoved()) {
0887: if (debugEnabled)
0888: log
0889: .debug("Clone for "
0890: + component.getComponentContext()
0891: .getPath()
0892: + " was flagged as removed, throwing an exception.");
0893: throw new ComponentNotFoundException(path);
0894: }
0895: if (debugEnabled)
0896: log
0897: .debug("'"
0898: + this .name
0899: + "':retrieveComponent() - returning clone for path '"
0900: + path + "'.");
0901: } else {
0902: CategoryManager categoryManager = contelligent
0903: .getCategoryManager();
0904: if (categoryManager.containsCategory(path)) {
0905: Map categoryMap = null;
0906: if (callData == null
0907: || (categoryMap = callData.getCategoryMap())
0908: .isEmpty()) {
0909: throw new ComponentNotFoundException(path);
0910: }
0911: path = exchangeCategories(path, categoryMap,
0912: categoryManager);
0913: }
0914:
0915: try {
0916: component = loadRawComponent(path, callData);
0917: initComponent(component, parentContainer);
0918: } catch (TypeException e) {
0919: throw new ComponentCreationException(
0920: ContelligentExceptionID.component_creation_invalidType,
0921: path, e);
0922: } catch (ComponentPersistenceException e) {
0923: throw new ComponentCreationException(
0924: ContelligentExceptionID.component_creation_persistence,
0925: path, e);
0926: } catch (ComponentNotFoundException e) {
0927: if (hasParent()) {
0928: return parent.retrieveComponent(path,
0929: parentContainer, callData, followLinks);
0930: } else {
0931: throw e;
0932: }
0933: }
0934: try {
0935: component.postCreate();
0936: } catch (Exception e) {
0937: log
0938: .error(
0939: "'"
0940: + this .name
0941: + "':retrieveComponent() - Exception while calling postCreate() on '"
0942: + component + "': ", e);
0943: throw new ComponentCreationException(
0944: ContelligentExceptionID.component_creation_persistence,
0945: path, e);
0946: }
0947: }
0948: // followLinks states whether or not to return proxies on ComponentLink
0949: // interfaced components
0950: if (followLinks && (component instanceof ComponentLink)) {
0951: component = ((ComponentLink) component).getProxyInstance();
0952: if (debugEnabled)
0953: log
0954: .debug("'"
0955: + this .name
0956: + "':retrieveComponent() - detected link at path '"
0957: + path
0958: + "', returning target componen [="
0959: + component + "] instead.");
0960: }
0961: if (debugEnabled) {
0962: log.debug("'" + this .name
0963: + "':retrieveComponent() - end with " + component
0964: + " of class " + component.getClass().getName());
0965: }
0966: return component;
0967: }
0968:
0969: final Component loadRawComponent(ComponentPath absolutePath,
0970: CallData callData) throws TypeException,
0971: ComponentPersistenceException, ComponentNotFoundException {
0972: final boolean debugEnabled = log.isDebugEnabled();
0973: ComponentContextImpl ctx = new ComponentContextImpl(this ,
0974: absolutePath, contelligent);
0975: componentAdapter.retrieve(ctx);
0976: if (debugEnabled)
0977: log
0978: .debug("'"
0979: + this .name
0980: + "':loadRawComponent() - meta-data for component '"
0981: + absolutePath + "' filled ...");
0982: if (!isRoot() && ctx.isRemoved()) {
0983: if (debugEnabled)
0984: log.debug("'" + this .name
0985: + "':loadRawComponent() - component '"
0986: + absolutePath + "' marked as deleted!");
0987: throw new ComponentNotFoundException(absolutePath);
0988: }
0989: String typeName = ctx.getTypeName();
0990: Type type = componentFactory.getType(typeName);
0991: Map propertyMap = ((ComponentPlaceholder) ctx.getComponent())
0992: .getProperties();
0993: Component component = componentFactory.createInstance(type,
0994: propertyMap);
0995: ctx.setType(type);
0996: ctx.setComponent(component);
0997: if (debugEnabled)
0998: log
0999: .debug("'"
1000: + this .name
1001: + "':loadRawComponent() - successfully loaded component '"
1002: + component + "'.");
1003: return component;
1004: }
1005:
1006: /**
1007: * Exchange all category tokens with valid values of the corresponding
1008: * category where a component does exist for in this or any parent manager.
1009: * This means the returned path does always exist either in this or a parent
1010: * manager. If no component is found for any catagory value (fallback values
1011: * are considered) a <code>ComponentNotFoundException</code> is thrown.
1012: * <BR>
1013: * Note that this method does NOT check whether path contains categories nor
1014: * whether categoryMap is emtpy!
1015: */
1016: final ComponentPath exchangeCategories(ComponentPath path,
1017: Map categoryMap, CategoryManager categoryManager)
1018: throws ComponentNotFoundException {
1019: final boolean debugEnabled = log.isDebugEnabled();
1020: final String[] pathArray = path.getParsedPath();
1021: ComponentPath actualPath = ComponentPath.ROOT_PATH
1022: .append(pathArray[0]);
1023: for (int a = 1; a < pathArray.length; a++) {
1024: if (!CategoryManager.CATEGORY_TOKEN.equals(pathArray[a])) {
1025: actualPath = actualPath.append(pathArray[a]);
1026: } else {
1027: if (debugEnabled) {
1028: log
1029: .debug("'"
1030: + this .name
1031: + "':exchangeCategories() - detected category-token in path '"
1032: + path + "' (element no. " + a
1033: + ") ...");
1034: }
1035: String categoryName = pathArray[a - 1];
1036: Category category = categoryManager
1037: .getCategory(categoryName);
1038: if (category == null) {
1039: throw new ComponentNotFoundException(
1040: ContelligentExceptionID.component_notFound_unknownCategory,
1041: new Object[] { category.getName(),
1042: new Integer(a - 1), path.toPath() });
1043: }
1044: String value = (String) categoryMap.get(categoryName);
1045: boolean found = false;
1046: while (value != null
1047: && !(found = componentExists(actualPath
1048: .append(value), true))) {
1049: value = category.getFallbackValue(value);
1050: }
1051: if (!found) {
1052: log
1053: .error("'"
1054: + this .name
1055: + "':exchangeCategories() - no component found for dir '"
1056: + actualPath + "' and value '"
1057: + value + "' of category '"
1058: + category + "', category-map="
1059: + categoryMap);
1060: throw new ComponentNotFoundException(path);
1061: }
1062: actualPath = actualPath.append(value);
1063: }
1064: }
1065: if (debugEnabled) {
1066: log
1067: .debug("'"
1068: + this .name
1069: + "':exchangeCategories() - replaced all categories in path '"
1070: + path + "' => path now '" + actualPath
1071: + "'.");
1072: }
1073: return actualPath;
1074: }
1075:
1076: /**
1077: * Implementation of {@link ComponentManager#componentExists(ComponentPath)}.
1078: * Simply calls {@link #componentExists(ComponentPath, boolean)} with 2nd
1079: * parameter true.
1080: */
1081: final public boolean componentExists(ComponentPath path) {
1082: return componentExists(path, true);
1083: }
1084:
1085: /**
1086: * Implementation of
1087: * {@link ComponentManager#componentExists(ComponentPath, boolean)}.
1088: */
1089: final public boolean componentExists(ComponentPath path,
1090: boolean inHierarchy) {
1091: try {
1092: if (isRootPath(path)) // the root container always exists
1093: return true;
1094:
1095: if (!isRoot()) {
1096: if (checkDeleted(path)) {
1097: return false;
1098: }
1099: }
1100:
1101: if (componentAdapter.exists(path.getDir(), path.getName()))
1102: return true;
1103:
1104: if (hasParent() && inHierarchy) {
1105: return getParent().componentExists(path, true);
1106: }
1107: } catch (ComponentPersistenceException e) {
1108: log
1109: .warn("'"
1110: + this .name
1111: + "':componentExists() - ComponentPersistenceException while checking for existence of component '"
1112: + path + "' (return false): " + e);
1113: }
1114: return false;
1115: }
1116:
1117: final boolean checkDeleted(ComponentPath path)
1118: throws ComponentPersistenceException {
1119: if (path == null || isRootPath(path)) {
1120: return false;
1121: }
1122: Component cloneComponent = getClone(path);
1123: if (cloneComponent != null) {
1124: if (cloneComponent.getComponentContext().isRemoved()) {
1125: return true;
1126: }
1127: }
1128: if (componentAdapter.deletedHierarchical(path)) {
1129: return true;
1130: } else {
1131: if (hasRecreatedParent(path)
1132: && !componentAdapter.exists(path.getDir(), path
1133: .getName())) {
1134: return true;
1135: } else {
1136: return false;
1137: }
1138: }
1139: }
1140:
1141: final boolean hasRecreatedParent(ComponentPath path)
1142: throws ComponentPersistenceException {
1143: ComponentPath parentPath = path.parentPath();
1144:
1145: if (parentPath == null) {
1146: return false;
1147: }
1148: Component cloneComponent = getClone(path);
1149: if (cloneComponent != null) {
1150: if (cloneComponent.getComponentContext().isRecreated()) {
1151: return true;
1152: }
1153: }
1154: if (componentAdapter.recreatedHierarchical(parentPath)) {
1155: return true;
1156: } else {
1157: return false;
1158: }
1159: }
1160:
1161: /**
1162: * Implementation of {@link ComponentManager#updateComponent}.
1163: */
1164: final public void updateComponent(Component component,
1165: CallData callData) throws ComponentPersistenceException,
1166: NoWritePermissionException, ModificationVetoException,
1167: ComponentNotFoundException, ComponentLockException,
1168: WouldCreateDeadRelationsException {
1169: if (callData == null) {
1170: log
1171: .error("'"
1172: + this .name
1173: + "':updateComponent() - cannot write a component without CallData!");
1174: throw new ComponentWriteException(
1175: "Cannot write a component without CallData - login first please!");
1176: }
1177: final ContelligentPrincipal caller = callData
1178: .getContelligentSession().getUser();
1179: if (!callerHasPermission(caller, callData, component,
1180: ComponentPermission.WRITE)) {
1181: log.warn("'" + this .name + "':updateComponent() - caller '"
1182: + caller + "' has no write access for component '"
1183: + component + "'!");
1184: throw new NoWritePermissionException(caller, component
1185: .getComponentContext().getPath());
1186: }
1187: ComponentPath path = component.getComponentContext().getPath();
1188: boolean locked = lockComponent(path, callData);
1189:
1190: try {
1191: ComponentContextImpl context = (ComponentContextImpl) component
1192: .getComponentContext();
1193: context.setModifiedBy(caller);
1194: if (isRoot() || componentExists(path, false)) {
1195: updateWrapper(context);
1196: } else {
1197: context.setPersistenceManager(this );
1198: componentAdapter.create(context);
1199: }
1200: relationsManager
1201: .updateRelations(component, callData, false);
1202: checkRelationsOfComponent(path, false, callData);
1203: fireChangeEvent(component);
1204: } finally {
1205: if (locked) {
1206: componentLockManager.unlockComponent(path, this , false,
1207: callData);
1208: }
1209: }
1210: if ((!isRoot()) && componentExists(path, false)) {
1211: componentLockManager.lockComponentShared(path, this ,
1212: callData);
1213: }
1214: }
1215:
1216: final void checkAvailableLock(CallData callData,
1217: ComponentPath component) throws ComponentLockException {
1218: componentLockManager.checkAvailableLock(component, callData);
1219: }
1220:
1221: /**
1222: * Implementation of {@link ComponentManager#copyComponentTree}.
1223: */
1224: final public Component copyComponentTree(CallData callData,
1225: ComponentPath sourcePath, ComponentPath targetParentPath,
1226: String toName) throws ComponentNotFoundException,
1227: ComponentPersistenceException, ComponentPathException,
1228: NoReadPermissionException, NoWritePermissionException,
1229: ComponentAlreadyExistsException, ModificationVetoException,
1230: ComponentLockException {
1231: return copyComponentTree(callData, sourcePath,
1232: targetParentPath, toName, CopyMode.LINK_FINALS, false);
1233: }
1234:
1235: /**
1236: * Implementation of {@link ComponentManager#copyComponentTree}.
1237: */
1238: final public Component copyComponentTree(CallData callData,
1239: ComponentPath sourcePath, ComponentPath targetParentPath,
1240: String toName, CopyMode mode, boolean cloningCopy)
1241: throws ComponentNotFoundException,
1242: ComponentPersistenceException, ComponentPathException,
1243: NoReadPermissionException, NoWritePermissionException,
1244: ComponentAlreadyExistsException, ModificationVetoException,
1245: ComponentLockException {
1246: Component sourceComponent = getComponent(sourcePath, callData,
1247: false);
1248: if (toName == null || toName.length() == 0)
1249: toName = sourceComponent.getComponentContext().getPath()
1250: .getName();
1251: ComponentPath targetPath = targetParentPath.append(toName);
1252:
1253: checkReadOnly(targetPath);
1254:
1255: final User caller = callData.getContelligentSession().getUser();
1256:
1257: Component targetParent = getComponent(targetParentPath,
1258: callData);
1259: if (!(targetParent instanceof Container)
1260: || (targetParent instanceof ComponentLink)) {
1261: log
1262: .warn("'"
1263: + this .name
1264: + "':copyComponentTree() - could not write component to path'"
1265: + targetPath + "' because '"
1266: + targetParentPath
1267: + "' is no container or a link-component!");
1268: throw new ComponentWriteException(
1269: ContelligentExceptionID.component_noContainer,
1270: new Object[] { targetPath.toPath() });
1271: }
1272: // check for self-copy:
1273: if (targetPath.isSubPathOf(sourcePath)
1274: || targetPath.equals(sourcePath)
1275: || sourcePath.isSubPathOf(targetPath)) {
1276: log
1277: .warn("'"
1278: + this .name
1279: + "':copyComponentTree() - cannot copy a component '"
1280: + sourceComponent
1281: + "' on itself! Use writeComponent() for this task!");
1282: throw new ComponentWriteException(
1283: ContelligentExceptionID.component_moveBeneathItself,
1284: new Object[] { sourceComponent
1285: .getComponentContext().getPath().toPath() });
1286: }
1287: // check write permission for target-path:
1288: if (!callerHasPermission(caller, callData, targetParent,
1289: ComponentPermission.WRITE)) {
1290: log.warn("'" + this .name
1291: + "':copyComponentTree() - caller '" + caller
1292: + "' has no write access for component '"
1293: + targetParent + "'!");
1294: throw new NoWritePermissionException(caller, targetParent
1295: .getComponentContext().getPath());
1296: }
1297:
1298: if (componentExists(targetPath)) {
1299: log.warn("Could not copy component '" + sourceComponent
1300: + "' because target-path '" + targetPath
1301: + "' already exists!");
1302: throw new ComponentAlreadyExistsException(targetPath);
1303: }
1304:
1305: if (!callerHasPermissionForTree(callData, caller,
1306: sourceComponent, ComponentPermission.READ)) {
1307: log
1308: .warn("'"
1309: + this .name
1310: + "':copyComponentTree() - caller has no read access for component-tree '"
1311: + sourcePath + "'!");
1312: throw new NoReadPermissionException(caller, sourcePath);
1313: }
1314:
1315: boolean locked = lockComponent(targetPath, callData);
1316: // now (recursivly) copy the whole tree:
1317: try {
1318: Component target = copyComponentTree(
1319: (Container) targetParent, caller, callData,
1320: sourceComponent, toName, mode);
1321: if (target != null) {
1322: fireAddEvent((Container) targetParent, target);
1323: }
1324:
1325: if (cloningCopy) {
1326:
1327: // Change internal references within the copied tree to point
1328: // to the same relative location within the new copy.
1329: // Note that we cant ask the RelationsManager for the relations
1330: // of our new copy before the transaction is committed, so we
1331: // have to grab the relation sources from the source tree and
1332: // calculate their respective positions within the copy.
1333:
1334: Set lockedComponents = new HashSet();
1335:
1336: List componentsToUpdate = new LinkedList();
1337:
1338: RelationsManagerImpl relationsManager = (RelationsManagerImpl) contelligent
1339: .getRelationsManager();
1340: Set pathsToUpdate = relationsManager
1341: .getTreeRelationSources(sourcePath, this
1342: .getId());
1343: Iterator sourcesFromTree = pathsToUpdate.iterator();
1344: while (sourcesFromTree.hasNext()) {
1345: ComponentPath path = (ComponentPath) sourcesFromTree
1346: .next();
1347: if (sourcePath.equals(path)
1348: || path.isSubPathOf(sourcePath)) {
1349: if (path.equals(sourcePath)) {
1350: path = targetPath;
1351: } else {
1352: path = path.exchangeParent(sourcePath,
1353: targetPath);
1354: }
1355: Component component = cloneComponent(path,
1356: callData);
1357: log.info("'" + this .name
1358: + "':moveComponentTree() - informing '"
1359: + component + "' about move of '"
1360: + sourcePath + "' to '" + targetPath
1361: + "' ... (component was copied)");
1362: try {
1363: relationsManager.updateRelationsForMove(
1364: component, sourcePath, targetPath);
1365: updateComponent(component, callData);
1366: } catch (ContelligentException ce) {
1367: throw new ComponentPersistenceException(ce);
1368: }
1369: }
1370: }
1371: }
1372:
1373: return target;
1374: } finally {
1375: if (!isRoot()) {
1376: componentLockManager.lockComponentShared(targetPath,
1377: this , callData);
1378: }
1379: if (locked) {
1380: unlockComponent(targetPath, callData);
1381: }
1382: }
1383: }
1384:
1385: /**
1386: * Implementation of
1387: * {@link ComponentManager#cloneComponent(ComponentPath, CallData)}.
1388: */
1389: final public Component cloneComponent(ComponentPath path,
1390: CallData callData) throws ComponentNotFoundException,
1391: ComponentCreationException {
1392: if (isRootPath(path))
1393: return getRootComponent();
1394:
1395: Component component = getClone(path);
1396: if (component != null) {
1397: if (log.isDebugEnabled()) {
1398: log
1399: .debug("'"
1400: + this .name
1401: + "':cloneComponent() - returning already cloned component '"
1402: + component + "'.");
1403: }
1404: return component;
1405: }
1406: if (contelligent.getCategoryManager().containsCategory(path)) {
1407: throw new ComponentCreationException(
1408: ContelligentExceptionID.component_creation_clone,
1409: path);
1410: }
1411: return cloneComponent(getComponent(path, callData, false)); // don't
1412: // follow
1413: // links
1414: }
1415:
1416: /**
1417: * Implementation of {@link ComponentManager#cloneComponent(Component)}.
1418: */
1419: final public Component cloneComponent(Component component)
1420: throws ComponentCreationException {
1421: final ComponentContextImpl orgCtx = (ComponentContextImpl) component
1422: .getComponentContext();
1423: final ComponentPath path = orgCtx.getPath();
1424: if (isRootPath(path))
1425: return getRootComponent();
1426:
1427: Component clonedComponent = getClone(path);
1428: if (clonedComponent != null) {
1429: if (log.isDebugEnabled()) {
1430: log
1431: .debug("'"
1432: + this .name
1433: + "':cloneComponent() - returning already cloned component '"
1434: + clonedComponent + "'.");
1435: }
1436: return clonedComponent;
1437: }
1438: ComponentContextImpl clonedCtx = (ComponentContextImpl) orgCtx
1439: .clone();
1440: Type type = orgCtx.getType();
1441: try {
1442: clonedComponent = componentFactory.createRawInstance(type); // throws
1443: // TypeException
1444: type.setProperties(clonedComponent, type.getProperties(
1445: component, false));
1446: clonedCtx.setComponent(clonedComponent);
1447: clonedComponent.postCreate();
1448: addClone(path, clonedComponent);
1449: if (log.isDebugEnabled()) {
1450: log
1451: .debug("'"
1452: + this .name
1453: + "':cloneComponent() - ... successfully cloned and initialized component '"
1454: + clonedComponent + "'.");
1455: }
1456: return clonedComponent;
1457: } catch (TypeException e) { // should never occur since we clone an already existing type !!
1458: log
1459: .error("'"
1460: + this .name
1461: + "':cloneComponent() - Exception while creating instance of type '"
1462: + type + "': " + e);
1463: throw new ComponentCreationException(
1464: ContelligentExceptionID.component_creation_invalidType,
1465: path, e);
1466: } catch (Exception e) {
1467: log
1468: .error(
1469: "'"
1470: + this .name
1471: + "':cloneComponent() - Exception while calling postCreate() on '"
1472: + clonedComponent + "': ", e);
1473: throw new ComponentCreationException(
1474: ContelligentExceptionID.component_creation_persistence,
1475: path, e);
1476: }
1477: }
1478:
1479: /**
1480: * Returns a newly created (yet not persistent!) component instance using
1481: * the specified type, name, acl and property-map. Note that
1482: * {@link #initComponent} gets called before returning the instance but NOT
1483: * {@link Component#postCreate} ! The calling method must invoke
1484: * {@link Component#postCreate} before any client code may access the
1485: * component! <BR>
1486: * If parameter <tt>propertyMap</tt> is non-null the instance gets those
1487: * properties set. A property may be overwritten only if the type does not
1488: * define that property as final. The map must contain either
1489: * (String,String) or (String,Double) entries.
1490: *
1491: * @exception TypeException
1492: * if the type is unknown
1493: * @exception ComponentCreationException
1494: * if the component could not be created
1495: * @exception ComponentPathException
1496: * if the name contains invalid characters
1497: * @see Type#setProperties
1498: */
1499: final Component newInstanceFromType(Container parent, String name,
1500: String typeName, AccessControlList acl, Map propertyMap,
1501: ComponentContextImpl orgCtx) throws TypeException,
1502: ComponentCreationException, ComponentPathException {
1503: final ComponentPath path = parent.getComponentContext()
1504: .getPath().append(name);
1505: if (log.isDebugEnabled()) {
1506: log.debug("'" + this .name
1507: + "':newInstanceFromType() - creating component '"
1508: + path + "' with type '" + typeName + "' ...");
1509: }
1510: Type type = componentFactory.getType(typeName);
1511: Component rawInstance = componentFactory.createInstance(type,
1512: propertyMap);
1513:
1514: ComponentContextImpl ctx = (orgCtx == null) ? new ComponentContextImpl(
1515: this , path, contelligent)
1516: : orgCtx.clone(this , path);
1517: ctx.setType(type);
1518: ctx.setTypeName(type.getName());
1519: ctx.setACL(acl);
1520: ctx.setComponent(rawInstance);
1521: ctx.setLastModified(TimeService.getInstance()
1522: .currentTimeMillis());
1523: initComponent(rawInstance, parent);
1524: return rawInstance;
1525: }
1526:
1527: /**
1528: * Implementation of {@link ComponentManager#createLink}.
1529: */
1530: final public ComponentLink createLink(Component linkTarget,
1531: Container parent, String name, AccessControlList acl,
1532: CallData callData) throws ComponentPersistenceException,
1533: ComponentCreationException, ModificationVetoException,
1534: ComponentPathException, ComponentLockException,
1535: ComponentAlreadyExistsException {
1536: // XXX: prevent creating a link on a link?
1537: try {
1538: Map propertyMap = new HashMap(2);
1539: propertyMap.put(DEFAULT_LINK_TYPE_PATH_PROPERTY, linkTarget
1540: .getComponentContext().getPath().toString());
1541: return (ComponentLink) createComponent(parent, name,
1542: DEFAULT_LINK_TYPE, propertyMap, acl, callData);
1543: } catch (TypeException e) {
1544: // this exception should never occure in a properly configured system:
1545: log
1546: .fatal("'"
1547: + this .name
1548: + "':createLink() - internal error: TypeException using default link type '"
1549: + DEFAULT_LINK_TYPE + "'!");
1550: throw new ComponentCreationException(
1551: ContelligentExceptionID.component_creation_invalidType,
1552: parent.getComponentContext().getPath().append(name));
1553: }
1554: }
1555:
1556: /**
1557: * Implementation of {@link ComponentManager#createComponent}.
1558: */
1559: final public Component createComponent(Container parent,
1560: String name, String typeName, Map propertyMap,
1561: AccessControlList acl, CallData callData)
1562: throws TypeException, ComponentPersistenceException,
1563: ComponentCreationException, ModificationVetoException,
1564: ComponentPathException, ComponentLockException,
1565: ComponentAlreadyExistsException {
1566: Type type = componentFactory.getType(typeName); // throws UnknownTypeException
1567: Map properties = null;
1568:
1569: if (propertyMap != null && propertyMap.size() > 0) {
1570: // given property map contains (String,String) entries only, convert
1571: // it into (String,String) or (String,Double) entries depending on
1572: // property-type.
1573: properties = type.getProperties(propertyMap, false);
1574: }
1575: return createComponent(parent, name, type, properties, acl,
1576: true, true, callData);
1577: }
1578:
1579: // propertyMap expected to contain (String,String) or (String,Double) like
1580: // Type.getProperties returns!
1581: final protected Component createComponent(Container parent,
1582: String name, Type type, Map propertyMap,
1583: AccessControlList acl, boolean postCreate,
1584: boolean updateRelations, CallData callData)
1585: throws TypeException, ComponentPersistenceException,
1586: ComponentCreationException, ModificationVetoException,
1587: ComponentPathException, ComponentLockException,
1588: ComponentAlreadyExistsException {
1589: final ComponentPath path = parent.getComponentContext()
1590: .getPath().append(name);
1591: final boolean debugEnabled = log.isDebugEnabled();
1592:
1593: checkReadOnly(path);
1594:
1595: boolean locked = lockComponent(path, callData);
1596: try {
1597: // is this a blueprint instantiation (mere copy) or a real creation?
1598: if (!isImport() && type.isBlueprint()
1599: && !path.equals(type.getBlueprintPath())) {
1600: if (debugEnabled) {
1601: log.debug("createComponent() - copying blueprint "
1602: + type.getBlueprintPath()
1603: + " for component " + name);
1604: }
1605: try {
1606: Component newInstance = copyComponentTree(callData,
1607: type.getBlueprintPath(), parent
1608: .getComponentContext().getPath(),
1609: name, CopyMode.BLUEPRINT, false);
1610: // assert: newInstance is a new clone
1611: ComponentContextImpl context = (ComponentContextImpl) newInstance
1612: .getComponentContext();
1613: context.setType(type);
1614: context.setTypeName(type.getName());
1615: context.setModifiedBy(callData
1616: .getContelligentSession().getUser());
1617: updateWrapper(context);
1618: return newInstance;
1619: } catch (ComponentNotFoundException cnfe) {
1620: throw new TypeException(
1621: ContelligentExceptionID.type_missingBlueprint,
1622: new Object[] { type.getName() });
1623: }
1624: } else {
1625: User caller = callData.getContelligentSession()
1626: .getUser();
1627: if (!callerHasPermission(caller, callData, parent,
1628: ComponentPermission.WRITE)) {
1629: log.warn("'" + this .name
1630: + "':createComponent() - caller '" + caller
1631: + "' has no write access for component '"
1632: + parent + "'!");
1633: throw new NoWritePermissionException(caller, parent
1634: .getComponentContext().getPath());
1635: }
1636:
1637: if (debugEnabled) {
1638: log
1639: .debug("'"
1640: + this .name
1641: + "':createComponent() - trying to create component '"
1642: + path + "' with type '"
1643: + type.getName() + "' ...");
1644: }
1645:
1646: if ((componentExists(path))
1647: && (!componentAdapter.deleted(path))) {
1648: log
1649: .error("'"
1650: + this .name
1651: + "':createComponent() - component with path '"
1652: + path + "' already exists");
1653: throw new ComponentAlreadyExistsException(path);
1654: }
1655:
1656: if (acl == null) {
1657: Set ownerSet = new HashSet(1);
1658: ownerSet.add(caller);
1659: acl = new AccessControlList(path.toString(),
1660: ownerSet);
1661: }
1662:
1663: Component newInstance = newInstanceFromType(parent,
1664: name, type.getName(), acl, propertyMap, null);
1665: ComponentContextImpl context = (ComponentContextImpl) newInstance
1666: .getComponentContext();
1667: context.setModifiedBy(caller);
1668: if (componentAdapter.deleted(context.getPath())) {
1669: log
1670: .debug("'"
1671: + this .name
1672: + "':createComponent() - detected creation of deleted component '"
1673: + context.getPath() + "' ...");
1674: Component clone = getClone(context.getPath());
1675: if (clone != null) { // we must use last-modified of
1676: // clone so DB may check for
1677: // concurrent modification
1678: context.setLastModified(clone
1679: .getComponentContext()
1680: .getLastModified());
1681: } else {
1682: context.setLastModified(componentAdapter
1683: .getLastModified(context));
1684: }
1685: updateWrapper(context);
1686: // to make queries for subcomponent names work in this
1687: // transaction we have to set the state here
1688: context
1689: .setStatus(ComponentPersistenceAdapter.RECREATED);
1690: } else {
1691: componentAdapter.create(context);
1692: }
1693:
1694: if (updateRelations) {
1695: relationsManager.updateRelations(newInstance,
1696: callData, false);
1697: }
1698: try {
1699: if (postCreate) {
1700: newInstance.postCreate();
1701: fireAddEvent(parent, newInstance);
1702: }
1703: addClone(path, newInstance);
1704: } catch (ComponentLockException e) {
1705: throw e;
1706: } catch (Exception e) {
1707: log
1708: .error(
1709: "'"
1710: + this .name
1711: + "':createComponent() - Exception while calling postCreate() on '"
1712: + newInstance + "': ", e);
1713: throw new ComponentCreationException(
1714: ContelligentExceptionID.component_creation_persistence,
1715: path, e);
1716: }
1717:
1718: return newInstance;
1719: }
1720: } finally {
1721: if (!isRoot()) {
1722: componentLockManager.lockComponentShared(path, this ,
1723: callData);
1724: }
1725: if (locked) {
1726: unlockComponent(path, callData);
1727: }
1728: }
1729: }
1730:
1731: /**
1732: * Implementation of {@link ComponentManager#deleteComponentTree}.
1733: */
1734: final public void deleteComponentTree(CallData callData,
1735: ComponentPath path) throws ContelligentException,
1736: NoDeletePermissionException, ModificationVetoException,
1737: RelationExistsException, ComponentLockException {
1738: deleteComponentTree(path, callData, true, true, true);
1739: }
1740:
1741: final void deleteComponentTree(ComponentPath path,
1742: CallData callData, boolean removeRelations,
1743: boolean checkRelations, boolean checkLinkContext)
1744: throws ContelligentException, NoDeletePermissionException,
1745: ModificationVetoException, RelationExistsException,
1746: ComponentLockException {
1747: deleteComponentTree(path, callData, removeRelations,
1748: checkRelations, checkLinkContext, false);
1749: }
1750:
1751: final void deleteComponentTree(ComponentPath path,
1752: CallData callData, boolean removeRelations,
1753: boolean checkRelations, boolean checkLinkContext,
1754: boolean committingDelete) throws ContelligentException,
1755: NoDeletePermissionException, ModificationVetoException,
1756: RelationExistsException, ComponentLockException {
1757:
1758: if (isRootPath(path)) {
1759: log
1760: .warn("'"
1761: + this .name
1762: + "':deleteComponentTree() - the root container cannot be deleted!");
1763: return;
1764: }
1765: if (!componentExists(path)) {
1766: if (log.isDebugEnabled())
1767: log.debug("'" + this .name
1768: + "':deleteComponentTree() - component '"
1769: + path + "' does not exists!");
1770: return;
1771: }
1772:
1773: checkContainsReadOnly(path);
1774:
1775: boolean locked = false;
1776: if (!committingDelete) {
1777: // Committing a subtree must be able to bypass these checks, since
1778: // in that case (and only in that case) deletes in Production must be
1779: // possible despite of shared locks. This is because the matching
1780: // shared lock is guaranteed to be in the context we are committing
1781: // right now.
1782: locked = lockComponentForDelete(path, callData,
1783: checkLinkContext);
1784: }
1785: try {
1786: Component toRemove = getComponent(path, callData, false); // don't follow links;
1787: final ContelligentPrincipal caller = callData
1788: .getContelligentSession().getUser();
1789: if (!callerHasPermissionForTree(callData, caller, toRemove,
1790: ComponentPermission.DELETE)) {
1791: log
1792: .warn("'"
1793: + this .name
1794: + "':deleteComponentTree() - caller has no right to delete component-tree '"
1795: + path + "'!");
1796: throw new NoDeletePermissionException(caller, path);
1797: }
1798:
1799: if (isRoot()) {
1800: componentLockManager.removeLocksForComponentTree(path);
1801: componentAdapter.delete(path, true, false);
1802: } else {
1803: if (!getParent().componentExists(path)) {
1804: // component was created in this component manager
1805: componentLockManager
1806: .removeLocksForComponentTree(path);
1807: componentAdapter.delete(path, true, false);
1808: } else {
1809: ComponentContextImpl ctx = (ComponentContextImpl) toRemove
1810: .getComponentContext();
1811: if (ctx.getPersistenceManager().getId() != this
1812: .getId()) {
1813: log
1814: .debug("Component does not originate in this manager, cloning it.");
1815: try {
1816: Component clonedComp = cloneForManager(
1817: path, this , callData);
1818: addClone(path, clonedComp);
1819: ctx = (ComponentContextImpl) clonedComp
1820: .getComponentContext();
1821: } catch (Exception e) {
1822: log.error("cloneForManager failed.");
1823: throw new ContelligentException(
1824: "cloneForManager failed: ", e);
1825: }
1826: }
1827: ctx.setRemoved();
1828: ctx.setModifiedBy(caller);
1829: componentAdapter.delete(path, true, true);
1830: if (componentAdapter.exists(path.getDir(), path
1831: .getName())) {
1832: if (!componentAdapter.deleted(path)) {
1833: updateWrapper(ctx);
1834: }
1835: } else {
1836: componentAdapter.create(ctx);
1837: }
1838: }
1839: }
1840: // Make sure any clones in the deleted tree also get properly
1841: // flagged as deleted (important for later lookups within this
1842: // transaction)
1843: Map map = (Map) cloneMap.get();
1844: if (map != null) {
1845: Iterator it = map.values().iterator();
1846: while (it.hasNext()) {
1847: ComponentContextImpl currentCtx = (ComponentContextImpl) ((Component) it
1848: .next()).getComponentContext();
1849: if (currentCtx.getPath().isSubPathOf(path)
1850: || currentCtx.getPath().equals(path)) {
1851: currentCtx.setRemoved();
1852: }
1853: }
1854: }
1855: // RELATION
1856: if (removeRelations)
1857: relationsManager.removeRelationsOfTree(path, this
1858: .getId());
1859: if (callData.shouldCheckRelations()) {
1860: if (checkRelations && !deadRelationsCheckDisabled) {
1861: Map relationsMap = relationsManager
1862: .getGlobalPathsRelatedToTree(path, false,
1863: this .getId());
1864: if (!isRoot()) { // we must check if the remaining paths aren't deleted in this manager!
1865: long parentId = parent.getId();
1866: Iterator entries = relationsMap.entrySet()
1867: .iterator();
1868: while (entries.hasNext()) {
1869: Map.Entry entry = (Map.Entry) entries
1870: .next();
1871: String targetPath = (String) entry.getKey();
1872: Set relatedPathSet = (Set) entry.getValue();
1873: Iterator relatedPaths = relatedPathSet
1874: .iterator();
1875: while (relatedPaths.hasNext()) {
1876: GlobalComponentPath relatedPath = (GlobalComponentPath) relatedPaths
1877: .next();
1878: if ((relatedPath
1879: .getPersistenceManagerId() == parentId)
1880: && (componentAdapter
1881: .deletedHierarchical(relatedPath) || componentAdapter
1882: .exists(
1883: relatedPath
1884: .getDir(),
1885: relatedPath
1886: .getName()))) {
1887: relatedPaths.remove();
1888: }
1889: }
1890: if (relatedPathSet.isEmpty())
1891: entries.remove();
1892: }
1893: }
1894: if (!relationsMap.isEmpty()) {
1895: // we must mark for rollback because the deletion
1896: // already happened in the db!
1897: callData.markForRollback();
1898: throw new WouldCreateDeadRelationsException(
1899: path, relationsMap);
1900: }
1901: }
1902: }
1903: Container parent = parentContainer(toRemove);
1904: fireDeleteEvent(parent, toRemove, committingDelete);
1905: } catch (ComponentNotFoundException e) {
1906: log
1907: .warn("'"
1908: + this .name
1909: + "':deleteComponentTree() - ComponentNotFoundException while fetching component '"
1910: + path
1911: + "' to removeType although componentExists() returned true right before! (ignored): "
1912: + e);
1913: } finally {
1914: if (!isRoot()) {
1915: componentLockManager.lockComponentShared(path, this ,
1916: callData);
1917: }
1918: if (locked) {
1919: unlockComponent(path, callData);
1920: }
1921: }
1922: }
1923:
1924: final public int getSubcomponentCount(Container container) {
1925: if (isRoot()) {
1926: return componentAdapter.getSubcomponentCount(container
1927: .getComponentContext().getPath());
1928: } else {
1929: return getSubcomponentNames(container).size();
1930: }
1931: }
1932:
1933: /**
1934: * Implementation of {@link ComponentManager#getSubcomponentNames}.
1935: */
1936: final public Set getSubcomponentNames(Container container) {
1937: long[] ids;
1938:
1939: if (container.getComponentContext().isRecreated()) {
1940: ids = new long[] { getId() };
1941: } else {
1942: ids = getIdsUpToRoot();
1943: }
1944: try {
1945: return componentAdapter.getSubComponentNames(container
1946: .getComponentContext().getPath(), ids);
1947: } catch (ComponentPersistenceException e) {
1948: log
1949: .error(
1950: "'"
1951: + this .name
1952: + "':getSubcomponentNames() - Exception while retrieving subcomponent-names for container '"
1953: + container + "': ", e);
1954: return Collections.EMPTY_SET;
1955: }
1956: }
1957:
1958: final public Iterator getSubcomponentNames(Container container,
1959: int start, int amount) {
1960: return getSubcomponentNames(container).iterator();
1961: }
1962:
1963: // final public Iterator getSubcomponentNames(Container container, int
1964: // start, int amount, SortKeyHolder sortKeyHolder) {
1965: // return getSubcomponentNames(container).iterator();
1966: // }
1967:
1968: public String toString() {
1969: return ("[BasicComponentManager '" + name + "']");
1970: }
1971:
1972: final protected boolean hasParent() {
1973: return getParent() != null;
1974: }
1975:
1976: // ==============================================================================
1977: // non-public methods
1978: // ==============================================================================
1979:
1980: /**
1981: * Creates the root component for the ComponentManager. This is a hardcoded
1982: * folder component that is not stored in the database.
1983: */
1984: final Container createRootContainer() throws Exception {
1985: Container rootContainer = new Folder();
1986: ComponentContextImpl ctx = new ComponentContextImpl(this ,
1987: ComponentPath.ROOT_PATH, contelligent);
1988: TypeImpl rootType = new TypeImpl(-1, ROOT_TYPENAME,
1989: ROOT_TYPEGROUP, DEFAULT_FOLDER_TYPE, null,
1990: Collections.EMPTY_MAP, Collections.EMPTY_MAP,
1991: Folder.class.getName(), false, null);
1992: ctx.setType(rootType);
1993: ctx.setTypeName(rootType.getName());
1994: ctx.setInheritSecurity(false);
1995: ctx.setACL(rootACL);
1996: ctx.setComponent(rootContainer);
1997: ctx.setModifiedBy(ContelligentSecurityManager.getSystemUser());
1998: ctx.setLastModified(TimeService.getInstance()
1999: .currentTimeMillis());
2000: initComponent(rootContainer, null);
2001: rootContainer.postCreate();
2002: return rootContainer;
2003: }
2004:
2005: final private AccessControlList createRootACL(
2006: ACLElement rootACLElement) throws ContelligentException {
2007: AccessControlList acl = null;
2008: try {
2009: acl = ComponentImport.createACLfromXML("root",
2010: rootACLElement, this );
2011: } catch (ContelligentException e) {
2012: log
2013: .error("'"
2014: + this .name
2015: + "':createRootACL() - ContelligentException: "
2016: + e);
2017: log.info("'" + this .name
2018: + "':createRootACL() - ... using default ACL ...");
2019: User defaultOwner = getDefaultOwner();
2020: AclEntry readAccess = new ComponentAccess(defaultOwner,
2021: ComponentPermission.READ, -1, -1, -1, -1);
2022: AclEntry writeAccess = new ComponentAccess(defaultOwner,
2023: ComponentPermission.WRITE, -1, -1, -1, -1);
2024: AclEntry deleteAccess = new ComponentAccess(defaultOwner,
2025: ComponentPermission.DELETE, -1, -1, -1, -1);
2026: acl = new AccessControlList("ROOT", defaultOwner);
2027: acl.addEntry(defaultOwner, readAccess);
2028: acl.addEntry(defaultOwner, writeAccess);
2029: acl.addEntry(defaultOwner, deleteAccess);
2030: }
2031: if (log.isDebugEnabled()) {
2032: log.debug("'" + this .name
2033: + "':createRootACL() - created acl '" + acl + "'.");
2034: }
2035: return acl;
2036: }
2037:
2038: final public boolean isRootPath(String path) {
2039: return (path.length() == 0 || String.valueOf(
2040: ComponentPath.SEPARATOR).equals(path));
2041: }
2042:
2043: final public boolean isRootPath(ComponentPath path) {
2044: return (ComponentPath.ROOT_PATH.equals(path));
2045: }
2046:
2047: final public ComponentPath getRootPath() {
2048: return ComponentPath.ROOT_PATH;
2049: }
2050:
2051: /**
2052: * Returns the user principal representing the default owner of this
2053: * component-manager. This user gets used whenever no caller is available,
2054: * for example when initially importing components.
2055: *
2056: * @return a <code>User</code> value
2057: */
2058: final public User getDefaultOwner() throws ContelligentException {
2059: return defaultOwner;
2060: }
2061:
2062: /**
2063: * Recursivly copies the component-tree starting with the given
2064: * {@link Component} to the specified dir without checking any permissions
2065: * nor asking the target container if its an {@link ObservingContainer}.
2066: * <BR>
2067: * Depending on parameter <tt>mode</tt> the copying of
2068: * {@link de.finix.contelligent.ComponentContext#isFinal} components varies:
2069: * <UL>
2070: * <LI> {@link CopyMode#NO_FINALS} - the copy process is interrupted and
2071: * null returned.
2072: * <LI> {@link CopyMode#LINK_FINALS} - a link gets created for the final
2073: * component.
2074: * <LI> {@link CopyMode#ALL} - everything gets copied.
2075: * <LI> {@link CopyMode#ALL_ACLS} - everything gets copied and defined ACLs
2076: * are replicated on the copy.
2077: * </UL>
2078: *
2079: * @return the root of the copied component tree or null if nothing was
2080: * copied.
2081: */
2082: final Component copyComponentTree(Container targetParent,
2083: User caller, CallData callData, Component source,
2084: String toName, CopyMode mode) throws TypeException,
2085: ComponentCreationException, ComponentPathException,
2086: ComponentPersistenceException, ComponentLockException,
2087: ModificationVetoException {
2088: final boolean debugEnabled = log.isDebugEnabled();
2089:
2090: if (mode == CopyMode.NO_FINALS
2091: && source.getComponentContext().isFinal()) {
2092: if (debugEnabled) {
2093: log
2094: .debug("'"
2095: + this .name
2096: + "':copyComponentTree() - ... copy process interrupted (actual target-parent='"
2097: + targetParent + "', child-name='"
2098: + toName + "') because source '"
2099: + source + "' is final and copy-mode="
2100: + mode);
2101: }
2102: return null;
2103: }
2104:
2105: if (debugEnabled) {
2106: log.debug("'" + this .name
2107: + "':copyComponentTree() - copying source '"
2108: + source + "' beneath target-parent '"
2109: + targetParent + "' with name '" + toName
2110: + "' (copy-mode=" + mode + ") ...");
2111: }
2112:
2113: ComponentContextImpl sourceCtx = (ComponentContextImpl) source
2114: .getComponentContext();
2115: String typeName = sourceCtx.getType().getName();
2116: AccessControlList newACL;
2117: if (mode == CopyMode.ALL_ACLS) {
2118: newACL = sourceCtx.getACL();
2119: } else {
2120: newACL = new AccessControlList("", caller);
2121: }
2122:
2123: boolean goDeeper = true;
2124: boolean fullCopy = true;
2125: Map propertyMap = null;
2126:
2127: if ((mode == CopyMode.LINK_FINALS || mode == CopyMode.BLUEPRINT)
2128: && sourceCtx.isFinal()) {
2129: if (debugEnabled) {
2130: log
2131: .debug("'"
2132: + this .name
2133: + "':copyComponentTree() - ... copy process interrupted (actual target-parent='"
2134: + targetParent
2135: + "', child-name='"
2136: + toName
2137: + "') because source component '"
2138: + source
2139: + "' is final and or we should explicitly create a link for it --> creating a link for path '"
2140: + source + "' !");
2141: }
2142: propertyMap = new HashMap(2);
2143: propertyMap.put(DEFAULT_LINK_TYPE_PATH_PROPERTY, sourceCtx
2144: .getPath().toString());
2145: typeName = DEFAULT_LINK_TYPE;
2146: goDeeper = false;
2147: fullCopy = false;
2148: } else {
2149: propertyMap = getPropertyMap(source, true);
2150: }
2151:
2152: Component copiedInstance = null;
2153: if (fullCopy) {
2154: copiedInstance = newInstanceFromType(targetParent, toName,
2155: typeName, newACL, propertyMap, sourceCtx);
2156: // if we copy a blueprint to create an instance, we do not copy the
2157: // template resources
2158: if (definesBlueprint(source) && mode == CopyMode.BLUEPRINT) {
2159: ((ComponentContextImpl) copiedInstance
2160: .getComponentContext())
2161: .setTemplateResources(Collections.EMPTY_MAP);
2162: }
2163: } else {
2164: copiedInstance = newInstanceFromType(targetParent, toName,
2165: typeName, newACL, propertyMap, null);
2166: }
2167:
2168: try {
2169: copiedInstance.postCreate();
2170: } catch (Exception e) {
2171: log
2172: .error(
2173: "'"
2174: + this .name
2175: + "':copyComponentTree() - Exception while calling postCreate() on '"
2176: + copiedInstance + "': ", e);
2177: throw new ComponentCreationException(
2178: ContelligentExceptionID.component_creation_persistence,
2179: targetParent.getComponentContext().getPath()
2180: .append(toName), e);
2181: }
2182:
2183: ComponentContextImpl context = (ComponentContextImpl) copiedInstance
2184: .getComponentContext();
2185: context.setModifiedBy(caller);
2186: if (!isRoot() && componentAdapter.deleted(context.getPath())) {
2187: context.setLastModified(componentAdapter
2188: .getLastModified(context));
2189: updateWrapper(context);
2190: } else {
2191: componentAdapter.create(context);
2192: }
2193: addClone(copiedInstance.getComponentContext().getPath(),
2194: copiedInstance);
2195: // fireAddEvent(targetParent, copiedInstance); // throws
2196: // ModificationVetoException, ComponentLockException
2197:
2198: relationsManager.updateRelations(copiedInstance, callData,
2199: false);
2200:
2201: if (goDeeper
2202: && (source instanceof Container)
2203: && ((copiedInstance instanceof Container) && !(copiedInstance instanceof ComponentLink))) {
2204: Container sourceContainer = (Container) source;
2205: Iterator subNames = getSubcomponentNames(sourceContainer)
2206: .iterator();
2207: while (subNames.hasNext()) {
2208: String subName = (String) subNames.next();
2209: ComponentPath newSourcePath = sourceCtx.getPath()
2210: .append(subName);
2211: try {
2212: Component newSource = getComponent(newSourcePath,
2213: callData, false); // don't
2214: // follow
2215: // links
2216: copyComponentTree((Container) copiedInstance,
2217: caller, callData, newSource, subName, mode);
2218: } catch (ComponentNotFoundException e) {
2219: log
2220: .error(
2221: "'"
2222: + this .name
2223: + "']:copyComponentTree() - error in getSubcomponentNames() algorithm? Got name '"
2224: + subName
2225: + "' from source component '"
2226: + source
2227: + "' but could not loadType '"
2228: + newSourcePath + "': ", e);
2229: }
2230: }
2231: }
2232: return copiedInstance;
2233: }
2234:
2235: final public boolean callerHasPermission(CallData callData,
2236: Component component, ComponentPermission permission) {
2237: return callerHasPermission(callData, component, permission,
2238: false);
2239: }
2240:
2241: final public boolean callerHasPermission(CallData callData,
2242: Component component, ComponentPermission permission,
2243: boolean ignoreAdmin) {
2244: ContelligentPrincipal caller = callData
2245: .getContelligentSession().getUser();
2246: return callerHasPermission(caller, callData, component,
2247: permission, ignoreAdmin);
2248: }
2249:
2250: /**
2251: * @deprecated use the method with calldata. This only provides API
2252: * compatibility.
2253: */
2254: final public boolean callerHasPermission(
2255: ContelligentPrincipal caller, Component component,
2256: ComponentPermission permission) {
2257:
2258: CallData callData = ThreadedMem.getCallData();
2259: return this .callerHasPermission(caller, callData, component,
2260: permission);
2261: }
2262:
2263: final public boolean callerHasPermission(
2264: ContelligentPrincipal caller, CallData callData,
2265: Component component, ComponentPermission permission) {
2266:
2267: return callerHasPermission(caller, callData, component,
2268: permission, false);
2269: }
2270:
2271: /**
2272: * @deprecated use the method with calldata. This only provides API
2273: * compatibility.
2274: */
2275: final public boolean callerHasPermission(
2276: ContelligentPrincipal caller, Component component,
2277: ComponentPermission permission, boolean ignoreAdmin) {
2278:
2279: CallData callData = ThreadedMem.getCallData();
2280: return this .callerHasPermission(caller, callData, component,
2281: permission, ignoreAdmin);
2282: }
2283:
2284: final public boolean callerHasPermission(
2285: ContelligentPrincipal caller, CallData callData,
2286: Component component, ComponentPermission permission,
2287: boolean ignoreAdmin) {
2288:
2289: // The root principal has permission to do everything, but for some
2290: // things (EXECUTE permission on config components) we still want
2291: // to check against the actual ACL. For that, the ignoreAdmin
2292: // flag can be specified.
2293: if (!ignoreAdmin) {
2294: if (ContelligentSecurityManager.getInstance().hasPrivilege(
2295: caller,
2296: ContelligentSecurityManager.Privilege.IGNORE_ACLS)) {
2297: return true;
2298: }
2299: }
2300:
2301: // The internal index user has READ permission everywhere
2302: if (permission == ComponentPermission.READ) {
2303: if (ContelligentSecurityManager.getInstance().isIndexUser(
2304: caller)) {
2305: return true;
2306: }
2307: }
2308:
2309: if (permission == ComponentPermission.EXECUTE) {
2310: // do not check execute permission via cm acl
2311: if (ignoreAdmin) {
2312: return ((ComponentContextImpl) component
2313: .getComponentContext()).getEffectiveACL()
2314: .checkRealPermission(caller, permission,
2315: callData);
2316: } else {
2317: return ((ComponentContextImpl) component
2318: .getComponentContext()).getEffectiveACL()
2319: .checkPermission(caller, permission, callData);
2320: }
2321: }
2322: if (getACL() == null
2323: || (getACL().isEmpty() || getACL().checkPermission(
2324: caller, permission, callData))) {
2325: if (ignoreAdmin) {
2326: return ((ComponentContextImpl) component
2327: .getComponentContext()).getEffectiveACL()
2328: .checkRealPermission(caller, permission,
2329: callData);
2330: } else {
2331: return ((ComponentContextImpl) component
2332: .getComponentContext()).getEffectiveACL()
2333: .checkPermission(caller, permission, callData);
2334: }
2335: } else {
2336: return false;
2337: }
2338: }
2339:
2340: final public boolean callerHasPermissionForTree(CallData callData,
2341: ContelligentPrincipal caller, Component component,
2342: ComponentPermission permission) {
2343: if ((!getACL().isEmpty())
2344: && (!getACL().checkPermission(caller, permission,
2345: callData))) {
2346: return false;
2347: }
2348:
2349: AccessControlList effectiveACL = ((ComponentContextImpl) component
2350: .getComponentContext()).getEffectiveACL();
2351: /*
2352: * FIXME: to enable permission inheritance across different managers we
2353: * must maybe step down and calculate acl recursivley in realtime ?
2354: */
2355: boolean result = effectiveACL.checkPermission(caller,
2356: permission, callData);
2357: if (result && (component instanceof Container)
2358: && (!(component instanceof ComponentLink))) {
2359: Iterator subNames = getSubcomponentNames(
2360: (Container) component).iterator();
2361: while (result && subNames.hasNext()) {
2362: ComponentPath subName = new ComponentPath(
2363: (String) subNames.next());
2364: try {
2365: Component child = getSubcomponent(
2366: (Container) component, subName, callData,
2367: false);
2368: // don't follow links
2369: result = callerHasPermissionForTree(callData,
2370: caller, child, permission);
2371: } catch (ComponentNotFoundException e) {
2372: log
2373: .error(
2374: "'"
2375: + this .name
2376: + "']:callerHasPermissionForTree() - error in getSubcomponentNames() algorithm? Got name '"
2377: + subName
2378: + "' from container '"
2379: + component
2380: + "' but could not loadType it: ",
2381: e);
2382: } catch (ComponentCreationException e) {
2383: // This is a normal condition on package uninstallation, so
2384: // we should not spam the log with stacktraces here.
2385: log
2386: .warn("'"
2387: + this .name
2388: + "']:callerHasPermissionForTree() - could not create subcomponent '"
2389: + subName
2390: + "' of component '"
2391: + component
2392: + "' (this component-tree is ignored for permission checking): "
2393: + e.getMessage() + "\n"
2394: + e.getNested().getMessage());
2395: }
2396: }
2397: }
2398: return result;
2399: }
2400:
2401: /**
2402: * Special cleanup routine for sorted folders whose namelist got out of sync
2403: * with the actual data. This may be caused by direct manipulation of
2404: * components on the database level, bypassing the Contelligent server.
2405: *
2406: * Due to the possibility of failure and subsequent rollback of the
2407: * transaction, this should only be called by the xml export class. One
2408: * reason this might fail is if the user viewing the component does not have
2409: * write permission to the sorted folder.
2410: */
2411: final public void cleanMissingSubcomponent(
2412: SortedFolder parentContainer, String subcomponentName)
2413: throws ModificationVetoException {
2414: ComponentPath parentPath = parentContainer
2415: .getComponentContext().getPath();
2416: ComponentPath childPath = parentPath.append(subcomponentName);
2417: addEvent(new ComponentEvent(ComponentEvent.REMOVE, childPath,
2418: this .name));
2419: CallData callData = ThreadedMem.getCallData();
2420: try {
2421: SortedFolder parentClone = (SortedFolder) cloneComponent(parentContainer);
2422: boolean changed = parentClone.subcomponentRemoved(callData,
2423: subcomponentName);
2424: if (changed) {
2425: ComponentContextImpl parentCtx = (ComponentContextImpl) parentClone
2426: .getComponentContext();
2427: boolean locked = lockComponent(parentPath, callData);
2428: parentCtx.setModifiedBy(callData
2429: .getContelligentSession().getUser());
2430: if (isRoot() || componentExists(parentPath, false)) {
2431: updateWrapper(parentCtx);
2432: } else {
2433: parentCtx.setPersistenceManager(this );
2434: componentAdapter.create(parentCtx);
2435: }
2436: fireChangeEvent(parentClone);
2437: if (log.isDebugEnabled())
2438: log
2439: .debug("'"
2440: + this .name
2441: + "':cleanMissingSubcomponent() - emitted change-event for container '"
2442: + parentClone + "'.");
2443: if (locked) {
2444: unlockComponent(parentPath, callData);
2445: }
2446: }
2447: } catch (Exception e) {
2448: callData.markForRollback();
2449: if (e instanceof ModificationVetoException) {
2450: throw (ModificationVetoException) e;
2451: } else {
2452: log
2453: .error(
2454: "'"
2455: + this .name
2456: + "':cleanMissingSubcomponent() - ContelligentException while trying to inform parent '"
2457: + parentContainer
2458: + "' about deletion of child '"
2459: + subcomponentName + "': ", e);
2460: throw new ModificationVetoException(e);
2461: }
2462: }
2463: }
2464:
2465: final void fireDeleteEvent(Container parentContainer,
2466: Component subComponent, boolean committingDelete)
2467: throws ModificationVetoException,
2468: ComponentPersistenceException, ComponentLockException {
2469: ComponentContext subCtx = subComponent.getComponentContext();
2470:
2471: addEvent(new ComponentEvent(ComponentEvent.REMOVE, subCtx
2472: .getPath(), this .name));
2473:
2474: if (!committingDelete) {
2475: CallData callData = ThreadedMem.getCallData();
2476: if (parentContainer instanceof ObservingContainer) {
2477: try {
2478: ObservingContainer parentClone = (ObservingContainer) cloneComponent(parentContainer);
2479: boolean changed = parentClone.subcomponentRemoved(
2480: callData, subComponent);
2481: if (changed) {
2482: ComponentContextImpl parentCtx = (ComponentContextImpl) parentClone
2483: .getComponentContext();
2484: ComponentPath parentPath = parentCtx.getPath();
2485: boolean locked = lockComponent(parentPath,
2486: ThreadedMem.getCallData());
2487: if (!isRoot()) {
2488: componentLockManager.lockComponentShared(
2489: parentPath, this , callData);
2490: }
2491: parentCtx.setModifiedBy(callData
2492: .getContelligentSession().getUser());
2493: if (isRoot()
2494: || componentExists(parentPath, false)) {
2495: updateWrapper(parentCtx);
2496: } else {
2497: parentCtx.setPersistenceManager(this );
2498: componentAdapter.create(parentCtx);
2499: }
2500: fireChangeEvent(parentClone);
2501: if (log.isDebugEnabled())
2502: log
2503: .debug("'"
2504: + this .name
2505: + "':fireDeleteEvent() - emitted change-event for container '"
2506: + parentClone + "'.");
2507: if (locked) {
2508: unlockComponent(parentPath, ThreadedMem
2509: .getCallData());
2510: }
2511: }
2512: } catch (ContelligentException e) {
2513: callData.markForRollback();
2514: if (e instanceof ModificationVetoException) {
2515: throw (ModificationVetoException) e;
2516: } else {
2517: log
2518: .error(
2519: "'"
2520: + this .name
2521: + "':fireDeleteEvent() - ContelligentException while trying to inform parent '"
2522: + parentContainer
2523: + "' about deletion of child '"
2524: + subComponent + "': ",
2525: e);
2526: throw new ModificationVetoException(e);
2527: }
2528: }
2529: }
2530: }
2531: }
2532:
2533: final void fireAddEvent(Container parentContainer,
2534: Component subComponent) throws ModificationVetoException,
2535: ComponentPersistenceException, ComponentLockException {
2536:
2537: addEvent(new ComponentEvent(ComponentEvent.ADD, subComponent,
2538: this .name));
2539:
2540: CallData callData = ThreadedMem.getCallData();
2541: if (parentContainer instanceof ObservingContainer) {
2542: try {
2543: ObservingContainer parentClone = (ObservingContainer) cloneComponent(parentContainer);
2544: boolean changed = parentClone.subcomponentAdded(
2545: callData, subComponent);
2546: if (changed) { // add change-event for parent
2547: ComponentContextImpl parentCtx = (ComponentContextImpl) parentClone
2548: .getComponentContext();
2549: ComponentPath parentPath = parentCtx.getPath();
2550: boolean locked = lockComponent(parentPath,
2551: ThreadedMem.getCallData());
2552: if (!isRoot()) {
2553: componentLockManager.lockComponentShared(
2554: parentPath, this , callData);
2555: }
2556: parentCtx.setModifiedBy(callData
2557: .getContelligentSession().getUser());
2558: if (isRoot() || componentExists(parentPath, false)) {
2559: updateWrapper(parentCtx);
2560: } else {
2561: parentCtx.setPersistenceManager(this );
2562: componentAdapter.create(parentCtx);
2563: }
2564: fireChangeEvent(parentClone);
2565: if (log.isDebugEnabled())
2566: log
2567: .debug("'"
2568: + this .name
2569: + "':fireAddEvent() - emitted change-event for container '"
2570: + parentClone + "'.");
2571: if (locked) {
2572: unlockComponent(parentPath, ThreadedMem
2573: .getCallData());
2574: }
2575: }
2576: } catch (ContelligentException e) {
2577: callData.markForRollback();
2578: if (e instanceof ModificationVetoException) {
2579: throw (ModificationVetoException) e;
2580: } else {
2581: log
2582: .error(
2583: "'"
2584: + this .name
2585: + "':fireAddEvent() - ContelligentException while trying to inform parent '"
2586: + parentContainer
2587: + "' about new child '"
2588: + subComponent + "': ", e);
2589: throw new ModificationVetoException(e);
2590: }
2591: }
2592: }
2593: }
2594:
2595: final void fireChangeEvent(Component component)
2596: throws ComponentNotFoundException,
2597: ModificationVetoException, ComponentLockException {
2598: ComponentContext ctx = component.getComponentContext();
2599: addEvent(new ComponentEvent(ComponentEvent.CHANGE, component,
2600: this .name));
2601:
2602: CallData callData = ThreadedMem.getCallData();
2603: Component parentContainer = getComponent(new ComponentPath(ctx
2604: .getPath().getDir()), callData);
2605: if (parentContainer instanceof ObservingContainer) {
2606: try {
2607: ObservingContainer parentClone = (ObservingContainer) cloneComponent(parentContainer);
2608: boolean changed = parentClone.subcomponentChanged(
2609: callData, component);
2610: if (changed) {
2611: ComponentContextImpl parentCtx = (ComponentContextImpl) parentClone
2612: .getComponentContext();
2613: ComponentPath parentPath = parentCtx.getPath();
2614: boolean locked = lockComponent(parentPath,
2615: ThreadedMem.getCallData());
2616: parentCtx.setModifiedBy(callData
2617: .getContelligentSession().getUser());
2618: if (isRoot() || componentExists(parentPath, false)) {
2619: updateWrapper(parentCtx);
2620: } else {
2621: parentCtx.setPersistenceManager(this );
2622: componentAdapter.create(parentCtx);
2623: }
2624: fireChangeEvent(parentClone);
2625: if (log.isDebugEnabled())
2626: log
2627: .debug("'"
2628: + this .name
2629: + "':fireChangeEvent() - emitted change-event for container '"
2630: + parentClone + "'.");
2631: if (locked) {
2632: unlockComponent(parentPath, ThreadedMem
2633: .getCallData());
2634: }
2635: }
2636: } catch (ContelligentException e) {
2637: callData.markForRollback();
2638: if (e instanceof ModificationVetoException) {
2639: throw (ModificationVetoException) e;
2640: } else {
2641: log
2642: .error(
2643: "'"
2644: + this .name
2645: + "':fireChangeEvent() - ContelligentException while trying to inform parent '"
2646: + parentContainer
2647: + "' about deletion of child '"
2648: + component + "': ", e);
2649: throw new ModificationVetoException(e);
2650: }
2651: }
2652: }
2653: }
2654:
2655: final void addClone(ComponentPath path, Component clone) {
2656: Map map = (Map) cloneMap.get();
2657: if (map == null) {
2658: map = new HashMap();
2659: cloneMap.set(map);
2660: }
2661: map.put(path, clone);
2662: }
2663:
2664: final Component getClone(ComponentPath path) {
2665: Map map = (Map) cloneMap.get();
2666: if (map != null)
2667: return (Component) map.get(path);
2668: else
2669: return null;
2670: }
2671:
2672: /*
2673: * final Component removeClone(ComponentPath path) { Map map =
2674: * (Map)cloneMap.get(); if (map!=null && map.containsKey(path)) return
2675: * (Component)map.removeType(path); else return null; }
2676: */
2677:
2678: final void addEvent(ComponentEvent event) {
2679: List list = (List) eventList.get();
2680: if (list == null) {
2681: list = new LinkedList();
2682: eventList.set(list);
2683: }
2684: list.add(event);
2685: EventQueue.getInstance().addEvent(event);
2686: }
2687:
2688: final ListIterator getEvents() {
2689: List list = (List) eventList.get();
2690: return ((list == null) ? null : Collections.unmodifiableList(
2691: list).listIterator());
2692: }
2693:
2694: final List getEventList() {
2695: List list = (List) eventList.get();
2696: return ((list == null) ? null : Collections
2697: .unmodifiableList(list));
2698: }
2699:
2700: /**
2701: * Initialize a raw component instance (set act and attributes inherited
2702: * from the parent.
2703: */
2704: final void initComponent(Component rawInstance,
2705: Container parentContainer)
2706: throws ComponentCreationException {
2707: final ComponentContextImpl ctx = (ComponentContextImpl) rawInstance
2708: .getComponentContext();
2709: final ComponentPath path = ctx.getPath();
2710: final boolean debugEnabled = log.isDebugEnabled();
2711:
2712: ComponentContextImpl parentCtx = null; // may remain null if
2713: // ctx.inheritSecurity()==false
2714: // !!
2715:
2716: // BUG FIX; IGNORE BULLSHIT PARAMETER
2717: // (looks like our callers try to save us the time of looking up the
2718: // component parent here... and then dont really send us the direct
2719: // parent container but some indirect ancestor, which makes a giant
2720: // mess of the ACLs)
2721: parentContainer = null;
2722:
2723: if (ctx.inheritSecurity()) {
2724: if (parentContainer == null)
2725: parentContainer = parentContainer(rawInstance);
2726: parentCtx = (ComponentContextImpl) parentContainer
2727: .getComponentContext();
2728:
2729: try {
2730: AccessControlList parentACL = parentCtx
2731: .getEffectiveACL();
2732: AccessControlList childACL = ctx.getACL();
2733: if (parentACL == null) {
2734: log
2735: .error("'"
2736: + this .name
2737: + "':initComponent() - parent ACL of component '"
2738: + path + "' is null!");
2739: // TODO: throw exception !!! (rs)
2740: ctx.setEffectiveACL(childACL);
2741: } else {
2742: AccessControlList effectiveACL = (AccessControlList) childACL
2743: .clone();
2744: effectiveACL.addACL(getSystemUser(), parentACL);
2745: if (debugEnabled)
2746: log
2747: .debug("'"
2748: + this .name
2749: + "':initComponent() - ... successfully merged parent- and own ACL!");
2750: ctx.setEffectiveACL(effectiveACL);
2751: }
2752: } catch (NotOwnerException e) {
2753: log
2754: .warn("'"
2755: + this .name
2756: + "':initComponent() - NotOwnerException while merging acls: "
2757: + e);
2758: // do nothing!
2759: }
2760: } else {
2761: ctx.setEffectiveACL(ctx.getACL());
2762: if (debugEnabled)
2763: log
2764: .debug("'"
2765: + this .name
2766: + "':initComponent() - ... inheritSecurity of component '"
2767: + path + "' is false!");
2768: }
2769:
2770: // ----- init security mode (https/http)
2771: if (rawInstance instanceof SecureComponent
2772: || ctx.definesSecureTransfer()
2773: || (ctx.inheritSecurity() && parentCtx
2774: .requiresSecureTransfer())) {
2775: ctx.setRequiresSecureTransfer(true);
2776: } else {
2777: ctx.setRequiresSecureTransfer(false);
2778: }
2779: }
2780:
2781: /**
2782: * Implementation of {@link ComponentManager#moveComponentTree}. <BR>
2783: * Algorithm works as follows:
2784: * <OL>
2785: * <LI> get paths of those components which have a relation into the moved
2786: * tree. (including those lying themselves inside the moved tree!)
2787: * <LI> for each of those components: - clone it - if it lies within the
2788: * source tree just change any affected paths - else attempt to lock it and
2789: * then change any affected paths
2790: * <LI> copy the source tree (using the cloned source components from step
2791: * 2a with maybe changed paths)
2792: * <LI> now update the components from step 2b. This can't be done before
2793: * step 3 or else the system may complain about missing link targets.
2794: * <LI> delete source tree and all relations originating from it. If this is
2795: * the root server we may check for any relations still existing to this
2796: * tree (which would mean our algorithm has a fault). In a child server we
2797: * can't because we will sure have relations to this tree because our
2798: * modified components were not yet written to the root server.
2799: * <LI> at the end we check for any dead-relations in the destination tree.
2800: * This would also reveal a bug in the algorithm.
2801: * </OL>
2802: * <B>Note that currently only one component tree per transaction may be
2803: * moved!</B>
2804: */
2805: final public Set moveComponentTree(ComponentPath source,
2806: ComponentPath destination, CallData callData)
2807: throws ContelligentException,
2808: ComponentPersistenceException, MissingPermissionException,
2809: ComponentAlreadyExistsException {
2810: Set lockedComponents = new HashSet();
2811:
2812: if (destination.equals(source)
2813: || destination.isSubPathOf(source)
2814: || source.isSubPathOf(destination)) {
2815: throw new ComponentMoveException(
2816: ContelligentExceptionID.component_moveBeneathItself,
2817: new Object[] { source.toPath() });
2818: }
2819: if (componentFactory.containsBlueprintPath(source)) {
2820: throw new ComponentMoveException(
2821: ContelligentExceptionID.component_moveBlueprint,
2822: new Object[] { source.toPath() });
2823: }
2824: try {
2825: List componentsToUpdate = new LinkedList();
2826:
2827: checkContainsReadOnly(source);
2828:
2829: RelationsManagerImpl relationsManager = (RelationsManagerImpl) contelligent
2830: .getRelationsManager();
2831: // Set pathsRelatedToTree =
2832: // relationsManager.getPathsRelatedToTree(source, true,
2833: // this.getId());
2834: // Due to .. references we need to process both references to as
2835: // well as all from the tree to be moved
2836: Set pathsToUpdate = relationsManager.getPathsRelatedToTree(
2837: source, false, this .getId());
2838: pathsToUpdate.addAll(relationsManager
2839: .getTreeRelationSources(source, this .getId()));
2840: Iterator sourcesRelatedToTree = pathsToUpdate.iterator();
2841: while (sourcesRelatedToTree.hasNext()) {
2842: ComponentPath path = (ComponentPath) sourcesRelatedToTree
2843: .next();
2844: Component component = cloneComponent(path, callData);
2845: if (source.equals(path) || path.isSubPathOf(source)) {
2846: log.debug("'" + this .name
2847: + "':moveComponentTree() - informing '"
2848: + component + "' about move of '" + source
2849: + "' to '" + destination
2850: + "' ... (component gets itself moved)");
2851: relationsManager.updateRelationsForMove(component,
2852: source, destination);
2853: } else {
2854: boolean locked = lockComponent(path, callData);
2855: log.debug("'" + this .name
2856: + "':moveComponentTree() - informing '"
2857: + component + "' about move of '" + source
2858: + "' to '" + destination + "' ...");
2859: relationsManager.updateRelationsForMove(component,
2860: source, destination);
2861: componentsToUpdate.add(component);
2862: if (locked) {
2863: unlockComponent(path, callData);
2864: }
2865: }
2866: }
2867:
2868: // all relations changed, now simply copy the source tree: (copy
2869: // uses clones)
2870: copyComponentTree(callData, source, destination
2871: .parentPath(), destination.getName(),
2872: CopyMode.ALL_ACLS, false);
2873:
2874: // now update those components which got not themselves moved.
2875: Iterator it = componentsToUpdate.iterator();
2876: while (it.hasNext()) {
2877: Component component = (Component) it.next();
2878: ComponentPath path = component.getComponentContext()
2879: .getPath();
2880: log
2881: .debug("'"
2882: + this .name
2883: + "':moveComponentTree() - now updating component '"
2884: + component + "' ...");
2885: updateComponent(component, callData);
2886: unlockComponent(path, callData);
2887: }
2888:
2889: // delete source tree: (only check for remaining links to this tree
2890: // if we are in root server)
2891: deleteComponentTree(source, callData, true, isRoot(), true);
2892:
2893: // check for dead-relations in destination:
2894: checkRelationsOfComponent(destination, true, callData);
2895:
2896: return lockedComponents;
2897: } catch (ContelligentException e) {
2898: throw e;
2899: } catch (ContelligentRuntimeException e) {
2900: throw e; // prevent this exception from beeing wrapped in a
2901: // ComponentMoveException
2902: } catch (Exception e) {
2903: callData.markForRollback();
2904: log
2905: .error(
2906: "'"
2907: + this .name
2908: + "':moveComponentTree() - Exception while moving '"
2909: + source + "' to '" + destination
2910: + "': ", e);
2911: throw new ComponentMoveException(
2912: ContelligentExceptionID.component_generic,
2913: new Object[] { source.toPath() }, e);
2914: }
2915: }
2916:
2917: final public Map getPropertyMap(Component component,
2918: boolean includeRN) throws TypeException {
2919: return getPropertyMap(component, includeRN, true);
2920: }
2921:
2922: final public Map getPropertyMap(Component component,
2923: boolean includeRN, boolean includeW) throws TypeException {
2924: Type type = component.getComponentContext().getType();
2925: return type.getProperties(component, includeRN, includeW);
2926: }
2927:
2928: /**
2929: * Implementation of {@link ComponentManager#getInstancesOfType}.
2930: */
2931: final public Set getInstancesOfType(ComponentPath treeRoot,
2932: String typeName) throws ComponentPersistenceException {
2933: long[] ids = getIdsUpToRoot();
2934: Set typeNames = new HashSet(2);
2935: typeNames.add(typeName);
2936: return componentAdapter.getComponentPathsForTypeInstances(
2937: treeRoot, typeNames, ids);
2938: }
2939:
2940: /**
2941: * Functions like getInstancesOfType, except that it searches across all
2942: * existing CMs.
2943: */
2944: final public Set getGlobalInstancesOfType(ComponentPath treeRoot,
2945: String typeName) throws ComponentPersistenceException {
2946: long[] ids = {};
2947: Set typeNames = new HashSet(2);
2948: typeNames.add(typeName);
2949: return componentAdapter.getComponentPathsForTypeInstances(
2950: treeRoot, typeNames, ids);
2951: }
2952:
2953: /**
2954: * Implementation of
2955: * {@link ComponentManager#getComponentsInSubtreeFilteredByType}.
2956: */
2957: final public Set getComponentsInSubtreeFilteredByType(
2958: ComponentPath treeRoot, Collection typeNames)
2959: throws ComponentPersistenceException {
2960: Set allTypeNames = new HashSet(typeNames);
2961: Iterator iterator = typeNames.iterator();
2962: while (iterator.hasNext()) {
2963: String typeName = (String) iterator.next();
2964: allTypeNames.addAll(componentFactory
2965: .getSubTypeNames(typeName));
2966: }
2967: long[] ids = getIdsUpToRoot();
2968: return componentAdapter.getComponentPathsForTypeInstances(
2969: treeRoot, allTypeNames, ids);
2970: }
2971:
2972: /**
2973: * Implementation of {@link ComponentManager#deleteType}.
2974: */
2975: final public Set deleteType(CallData callData, String typeName,
2976: boolean force, boolean includeBlueprintComponent)
2977: throws ContelligentException,
2978: ComponentPersistenceException, NoDeletePermissionException,
2979: ModificationVetoException, ComponentLockException,
2980: RelationExistsException {
2981: // XXX: as long as we don't have one ComponentFactory per manager we
2982: // can't allow
2983: // the deletion of types in a non-root manager! (rs, 2002/11/18)
2984: if (!isRoot()) {
2985: log
2986: .error("'"
2987: + this .name
2988: + "':deleteType() - deletion of types not allowed in non-root manager!");
2989: throw new TypeException(
2990: ContelligentExceptionID.type_noModificationInContext);
2991: }
2992:
2993: Set pathsOfTypeInstances = this .getGlobalInstancesOfType(null,
2994: typeName);
2995: if (!force && !pathsOfTypeInstances.isEmpty()) {
2996: throw new TypeException(
2997: ContelligentExceptionID.type_instancesExist,
2998: new Object[] { typeName, pathsOfTypeInstances },
2999: pathsOfTypeInstances);
3000: }
3001:
3002: ContelligentEvent event = new TypeEvent(TypeEvent.DELETED,
3003: this .name, typeName);
3004: EventQueue.getInstance().addEvent(event);
3005:
3006: Set lockedComponents = new HashSet();
3007: if (pathsOfTypeInstances != null) {
3008: for (Iterator it = pathsOfTypeInstances.iterator(); it
3009: .hasNext();) {
3010: ComponentPath path = (ComponentPath) it.next();
3011: boolean locked = lockComponent(path, callData);
3012: deleteComponentTree(callData, path);
3013: if (locked) {
3014: unlockComponent(path, callData);
3015: } else {
3016: lockedComponents.add(path);
3017: }
3018: }
3019: }
3020: if (includeBlueprintComponent) {
3021: ComponentPath path = componentFactory.getType(typeName)
3022: .getBlueprintPath();
3023: if (path != null) {
3024: boolean locked = lockComponent(path, callData);
3025: deleteComponentTree(callData, path);
3026: if (locked) {
3027: unlockComponent(path, callData);
3028: } else {
3029: lockedComponents.add(path);
3030: }
3031: }
3032: }
3033: // throws exception if type has any subtypes or if type does not exist
3034: componentFactory.deleteType(typeName);
3035: return lockedComponents;
3036: }
3037:
3038: /**
3039: * Delete the given type without touching instances. Answer true if
3040: * instances exist. For internal use only and therefore not in the
3041: * interface.
3042: *
3043: * @param callData
3044: * @param typeName
3045: * @return
3046: * @throws ContelligentException
3047: * @throws ComponentPersistenceException
3048: * @throws NoDeletePermissionException
3049: * @throws ModificationVetoException
3050: * @throws ComponentLockException
3051: * @throws RelationExistsException
3052: */
3053: final boolean deleteTypeRaw(CallData callData, String typeName)
3054: throws ContelligentException,
3055: ComponentPersistenceException, NoDeletePermissionException,
3056: ModificationVetoException, ComponentLockException,
3057: RelationExistsException {
3058: // XXX: as long as we don't have one ComponentFactory per manager we
3059: // can't allow
3060: // the deletion of types in a non-root manager! (rs, 2002/11/18)
3061: if (!isRoot()) {
3062: log
3063: .error("'"
3064: + this .name
3065: + "':deleteType() - deletion of types not allowed in non-root manager!");
3066: throw new TypeException(
3067: ContelligentExceptionID.type_noModificationInContext);
3068: }
3069:
3070: Set pathsOfTypeInstances = this .getInstancesOfType(null,
3071: typeName);
3072:
3073: ContelligentEvent event = new TypeEvent(TypeEvent.DELETED,
3074: this .name, typeName);
3075: EventQueue.getInstance().addEvent(event);
3076:
3077: boolean subtypes = componentFactory.deleteTypeRaw(typeName);
3078: return (!pathsOfTypeInstances.isEmpty()) || subtypes;
3079: }
3080:
3081: final void flagTypeForUpgrade(CallData callData, String typeName)
3082: throws ContelligentException,
3083: ComponentPersistenceException, NoDeletePermissionException,
3084: ModificationVetoException, ComponentLockException,
3085: RelationExistsException {
3086: if (!isRoot()) {
3087: log
3088: .error("'"
3089: + this .name
3090: + "':flagTypeForUpgrade() - modification of types not allowed in non-root manager!");
3091: throw new TypeException(
3092: ContelligentExceptionID.type_noModificationInContext);
3093: }
3094: componentFactory.flagTypeForUpgrade(typeName);
3095: }
3096:
3097: final void checkUpgradedTypes() throws TypeException {
3098: componentFactory.checkUpgradedTypes();
3099: }
3100:
3101: /**
3102: * Implementation of {@link ComponentManager#renameType}.
3103: */
3104: final public Set renameType(CallData callData, String typeName,
3105: String newTypeName) throws TypeException,
3106: ComponentPersistenceException, ComponentLockException,
3107: ModificationVetoException {
3108: // XXX: as long as we don't have one ComponentFactory per manager we
3109: // can't allow
3110: // renaming of types in a non-root manager! (rs, 2002/11/18)
3111: if (!isRoot()) {
3112: log
3113: .error("'"
3114: + this .name
3115: + "':renameType() - renaming of types not allowed in non-root manager!");
3116: throw new TypeException(
3117: ContelligentExceptionID.type_noModificationInContext);
3118: }
3119:
3120: Set pathsOfTypeInstances = this .getGlobalInstancesOfType(null,
3121: typeName);
3122: Set changedComponents = new HashSet(); // only used to fire
3123: // component-events after
3124: // type-events
3125: Set lockedComponents = new HashSet();
3126: if (!pathsOfTypeInstances.isEmpty()) {
3127: for (Iterator it = pathsOfTypeInstances.iterator(); it
3128: .hasNext();) {
3129: ComponentPath path = (ComponentPath) it.next();
3130: boolean locked = lockComponent(path, callData);
3131: try {
3132: Component component = cloneComponent(path, callData);
3133: ComponentContextImpl context = (ComponentContextImpl) component
3134: .getComponentContext();
3135: context.setTypeName(newTypeName);
3136: context.setModifiedBy(callData
3137: .getContelligentSession().getUser());
3138: if (isRoot() || componentExists(path, false)) {
3139: updateWrapper(context);
3140: } else {
3141: context.setPersistenceManager(this );
3142: componentAdapter
3143: .create((ComponentContextImpl) component
3144: .getComponentContext());
3145: }
3146: changedComponents.add(component);
3147: if (locked) {
3148: unlockComponent(path, callData);
3149: } else {
3150: lockedComponents.add(path);
3151: }
3152: } catch (ComponentNotFoundException cnfe) {
3153: log
3154: .warn("renameType() - can not change type for component '"
3155: + path.toPath()
3156: + "', component does not exist.");
3157: }
3158: }
3159: }
3160:
3161: // throws exception if type has any subtypes or if type does not exist
3162: componentFactory.renameType(typeName, newTypeName);
3163:
3164: ContelligentEvent event = new TypeEvent(TypeEvent.DELETED,
3165: this .name, typeName);
3166: EventQueue.getInstance().addEvent(event);
3167:
3168: Type newType = componentFactory.getType(newTypeName);
3169: event = new TypeEvent(TypeEvent.CREATION, this .name, newType);
3170: EventQueue.getInstance().addEvent(event);
3171:
3172: Iterator chgComponents = changedComponents.iterator();
3173: while (chgComponents.hasNext()) {
3174: Component comp = (Component) chgComponents.next();
3175: try {
3176: fireChangeEvent(comp);
3177: } catch (ComponentNotFoundException e) {
3178: log
3179: .warn("renameType() - unable to fire change-event for component '"
3180: + comp + "': " + e);
3181: }
3182: }
3183:
3184: return lockedComponents;
3185: }
3186:
3187: /**
3188: * Implementation of {@link ComponentManager#createType}.
3189: */
3190: final public void createType(TypeElement typeDefinition)
3191: throws TypeException {
3192: // XXX: as long as we don't have one ComponentFactory per manager we
3193: // can't allow
3194: // the creation of types in a non-root manager! But we need to call this
3195: // method during import so we allow it for import manager. (rs,
3196: // 2002/11/18)
3197: if (isRoot() || isImport()) {
3198: boolean update = componentFactory.exists(typeDefinition
3199: .getName());
3200: if (update && !isImport()) {
3201: Type oldType = componentFactory.getType(typeDefinition
3202: .getName());
3203: String pathOfExistingBlueprint = "";
3204: if (oldType.isBlueprint()) {
3205: pathOfExistingBlueprint = componentFactory.getType(
3206: typeDefinition.getName())
3207: .getBlueprintPath().toString();
3208: }
3209: String pathOfAttemptedBlueprint = typeDefinition
3210: .getBlueprintPath();
3211: // creation is only allowed when you are changing the blueprint.
3212: // same type name and different component path means:
3213: // trying to create a blueprint with a name already in use
3214: if (!oldType.isBlueprint()
3215: || !pathOfExistingBlueprint
3216: .equals(pathOfAttemptedBlueprint)) {
3217: log
3218: .error("'"
3219: + this .name
3220: + "':createType() - failing to create a new type because name '"
3221: + typeDefinition.getName()
3222: + "' is already in use.");
3223: throw new TypeException(
3224: ContelligentExceptionID.type_alreadyExist,
3225: new String[] { typeDefinition.getName() });
3226: }
3227: }
3228: Type type = componentFactory.createType(typeDefinition);
3229: ContelligentEvent event = new TypeEvent(
3230: (update ? TypeEvent.CHANGED : TypeEvent.CREATION),
3231: this .name, type);
3232: EventQueue.getInstance().addEvent(event);
3233: } else {
3234: log
3235: .error("'"
3236: + this .name
3237: + "':createType() - creation of types only allowed in root- or import-manager!");
3238: throw new TypeException(
3239: ContelligentExceptionID.type_noModificationInContext);
3240: }
3241: }
3242:
3243: final public void exportTypes(Writer writer, boolean omitHeader,
3244: String prefix) throws IOException {
3245: componentFactory.exportTypes(writer, omitHeader, prefix);
3246: }
3247:
3248: final public Type getBlueprintType(ComponentPath componentPath) {
3249: return componentFactory.getBlueprintType(componentPath);
3250: }
3251:
3252: final public boolean isBlueprintInstance(Component component) {
3253: if (component != null) {
3254: Type type = component.getComponentContext().getType();
3255: return (type.getBlueprintPath() != null);
3256: }
3257: return false;
3258: }
3259:
3260: final public boolean definesBlueprint(Component component) {
3261: if (component != null) {
3262: return componentFactory.isBlueprintPath(component
3263: .getComponentContext().getPath());
3264: }
3265: return false;
3266: }
3267:
3268: /**
3269: * Implementation of {@link TxSynchronization#beforeCompletion}.
3270: */
3271: public boolean beforeCompletion() {
3272: Boolean informParent = (Boolean) parentInTransaction.get();
3273: if (informParent == Boolean.TRUE) {
3274: parent.beforeCompletion();
3275: }
3276: return true;
3277: }
3278:
3279: // FIXME: because we store all the events and clones in thread-locals
3280: // only one manager per tx is allowed! Can we go with this?
3281: // The only situation where we need two managers per tx is when one manager
3282: // gets merged into another. Since the merged one is empty aftwerwards this
3283: // should be no problem.
3284: /**
3285: * Implementation of {@link TxSynchronization#afterCompletion}. <B>If any
3286: * subclass overwrites this method it must call this method at the end so
3287: * thread-locals are reseted!</B>
3288: */
3289: public void afterCompletion(int status) {
3290: Boolean informParent = (Boolean) parentInTransaction.get();
3291:
3292: if (informParent == Boolean.TRUE) {
3293: parent.afterCompletion(status);
3294: }
3295:
3296: if (!isRoot() && (status == Status.STATUS_COMMITTED)) {
3297: List fileNameList = (List) filesToMoveList.get();
3298: if (fileNameList != null && fileNameList.size() > 0) {
3299: this .fileAdapter.moveFiles(fileNameList, getParent()
3300: .getFileAdapter());
3301: if (!fileNameList.isEmpty()) {
3302: log
3303: .error("'"
3304: + name
3305: + "':afterCompletion() - error while moving external files into parent, remaining files= "
3306: + fileNameList);
3307: }
3308: }
3309: }
3310:
3311: Boolean flag = (Boolean) destroyFileAdapters.get();
3312: if (flag != null && flag.booleanValue() == true) {
3313: fileAdapter.destroy();
3314: destroyFileAdapters.set(null);
3315: }
3316: }
3317:
3318: public void clean() {
3319: parentInTransaction.set(null);
3320: cloneMap.set(null);
3321: eventList.set(null);
3322: }
3323:
3324: /**
3325: * Implementation of {@link ComponentManager#getId}.
3326: */
3327: final public long getId() {
3328: return componentAdapter.getCMId();
3329: }
3330:
3331: /**
3332: * Returns all ids from this manager up to the root manager in order of the
3333: * hierarchy. First entry is the id of this manager.
3334: */
3335: final public long[] getIdsUpToRoot() {
3336: if (this .isRoot()) {
3337: return new long[] { this .getId() };
3338: } else {
3339: int count = 1;
3340: ComponentManager manager = this .getParent();
3341: while (manager != null) {
3342: count++;
3343: manager = manager.getParent();
3344: }
3345: long[] ids = new long[count];
3346: count = 0;
3347: manager = this ;
3348: while (manager != null) {
3349: ids[count++] = manager.getId();
3350: manager = manager.getParent();
3351: }
3352: return ids;
3353: }
3354: }
3355:
3356: /**
3357: * Implementation of {@link ComponentManager#lockComponent}.
3358: */
3359: final public boolean lockComponent(ComponentPath componentPath,
3360: CallData callData) throws ComponentPersistenceException,
3361: ComponentAlreadyLockedException, ComponentLockException,
3362: MissingPermissionException {
3363: return lockComponent(componentPath, callData, true);
3364: }
3365:
3366: final protected boolean lockComponent(ComponentPath componentPath,
3367: CallData callData, boolean checkLockContext)
3368: throws ComponentPersistenceException,
3369: ComponentAlreadyLockedException, ComponentLockException,
3370: MissingPermissionException {
3371: if (componentLockManager.isLockedLocally(componentPath)) {
3372: if (checkLockContext) {
3373: checkAvailableLock(callData, componentPath);
3374: }
3375: return false;
3376: }
3377: componentLockManager.lockComponent(componentPath, this ,
3378: callData);
3379: return true;
3380: }
3381:
3382: final protected boolean lockComponentForDelete(
3383: ComponentPath componentPath, CallData callData,
3384: boolean checkLockContext)
3385: throws ComponentPersistenceException,
3386: ComponentAlreadyLockedException, ComponentLockException,
3387: MissingPermissionException {
3388: componentLockManager.checkSharedLocksForDelete(componentPath,
3389: this , callData);
3390: if (componentLockManager.isLockedLocally(componentPath)) {
3391: if (checkLockContext) {
3392: checkAvailableLock(callData, componentPath);
3393: }
3394: return false;
3395: }
3396: componentLockManager.lockComponentForDelete(componentPath,
3397: this , callData);
3398: return true;
3399: }
3400:
3401: /**
3402: * Implementation of {@link ComponentManager#unlockComponent}.
3403: */
3404: final public void unlockComponent(ComponentPath componentPath,
3405: CallData callData) throws ComponentPersistenceException {
3406: componentLockManager.unlockComponent(componentPath, this ,
3407: false, callData);
3408: }
3409:
3410: /**
3411: * Implementation of {@link ComponentManager#isLocked}.
3412: */
3413: final public boolean isLocked(ComponentPath componentPath) {
3414: return componentLockManager.isLocked(componentPath);
3415: }
3416:
3417: final public List createEventsForAllLocks() {
3418: return componentLockManager.createEventsForAllLocks();
3419: }
3420:
3421: /**
3422: * Implementation of {@link ComponentManager#passLock}.
3423: */
3424: final public void passLock(ComponentPath componentPath,
3425: String toPrincipal, CallData callData)
3426: throws ComponentPersistenceException {
3427: componentLockManager.passLock(componentPath, toPrincipal,
3428: callData);
3429: }
3430:
3431: /**
3432: * Answer the acl of this manager.
3433: *
3434: * @return
3435: */
3436: final public AccessControlList getACL() {
3437: return acl;
3438: }
3439:
3440: final public void setACL(CallData callData, AccessControlList acl)
3441: throws ComponentPersistenceException {
3442: if (getACL().isOwner(callData.getUser())
3443: || ContelligentSecurityManager
3444: .getInstance()
3445: .hasPrivilege(
3446: callData.getUser(),
3447: ContelligentSecurityManager.Privilege.IGNORE_OWNERSHIP)) {
3448: this .acl = acl;
3449: contelligent.getComponentManagerHierarchy().storeACL(
3450: getName(), acl);
3451: } else {
3452: throw new NotOwnerException(callData.getUser(), getACL()
3453: .getName());
3454: }
3455: }
3456:
3457: final public Component updateComponent(
3458: ComponentElement componentElement, CallData callData)
3459: throws ContelligentException {
3460: ComponentPath path = getComponentPath(componentElement);
3461: boolean locked = lockComponent(path, callData);
3462:
3463: try {
3464: Component component = cloneComponent(
3465: getComponentPath(componentElement), callData);
3466: final ContelligentPrincipal caller = callData
3467: .getContelligentSession().getUser();
3468: if (!callerHasPermission(caller, callData, component,
3469: ComponentPermission.WRITE)) {
3470: log.warn("'" + this .name
3471: + "':updateComponent() - caller '" + caller
3472: + "' has no write access for component '"
3473: + component + "'!");
3474: throw new NoWritePermissionException(caller, component
3475: .getComponentContext().getPath());
3476: }
3477: updateComponent(component, componentElement, callData);
3478: // also updates relations and checks for dead relations resulting
3479: // from update
3480: fireChangeEvent(component);
3481: return component;
3482: } finally {
3483: if (locked) {
3484: unlockComponent(path, callData);
3485: }
3486: if ((!isRoot()) && componentExists(path, false)
3487: && (!componentLockManager.isLockedShared(path))) {
3488: componentLockManager.lockComponentShared(path, this ,
3489: callData);
3490: }
3491: }
3492: }
3493:
3494: /**
3495: * Updates a contelligent component using the given
3496: * <code>ComponentElement</code>. Any relations of the component are
3497: * updated and if this is not an import server a check for dead relations
3498: * caused by this update is performed too.
3499: *
3500: * @param componentElement
3501: * a contelligent component as XML element.
3502: */
3503: final private void updateComponent(Component component,
3504: ComponentElement componentElement, CallData callData)
3505: throws ContelligentException {
3506: // assert: component is a new component or a clone of an existing
3507: // component
3508:
3509: checkReadOnly(component.getComponentContext().getPath());
3510: CategoryManager categoryManager = contelligent
3511: .getCategoryManager();
3512:
3513: String name = componentElement.getName();
3514: String typeName = componentElement.getType();
3515: String directory = componentElement.getDir();
3516: String pathName = directory + name;
3517:
3518: ComponentMetainfoElement metainfoElement = componentElement
3519: .getMetainfoElement();
3520: ComponentSecurityElement securityElement = metainfoElement
3521: .getSecurityElement();
3522:
3523: List contentResourceElements = componentElement.getResources();
3524: List templateResourceElements = componentElement
3525: .getTemplateResourceList();
3526: boolean isFinal = new Boolean(metainfoElement.getIsFinal())
3527: .booleanValue();
3528: String composedBlueprint = metainfoElement
3529: .getComposedBlueprint();
3530: ComponentContextImpl context = (ComponentContextImpl) component
3531: .getComponentContext();
3532:
3533: // change type if it has changed to a subtype of old one:
3534: if (!typeName.equals(context.getTypeName())) {
3535: Type newType = componentFactory.getType(typeName);
3536: // XXX: do we allow subtypes which extend the actual type or only
3537: // restricted ones?
3538: if (componentFactory.isSubType(newType, context
3539: .getTypeName())) {
3540: context.setType(newType);
3541: context.setTypeName(typeName);
3542: } else {
3543: throw new ContelligentException(
3544: "Can not set new type '" + typeName
3545: + "', is no subtype of old type!");
3546: }
3547: }
3548:
3549: Map properties = ComponentImport
3550: .createPropertyMapFromXML(componentElement);
3551: Metadata metadata = context.getMetadata();
3552: ComponentImport.loadMetadataFromXML(componentElement, metadata);
3553:
3554: AccessControlList acl = null;
3555:
3556: if (securityElement != null) {
3557: acl = ComponentImport.createACLfromXML(pathName,
3558: securityElement, this );
3559: context.setDefinesSecureTransfer(securityElement
3560: .definesSecureTransfer());
3561: }
3562:
3563: try {
3564: Set sensitiveTemplateCategories = ComponentImport
3565: .sensitiveCategoriesFromXML(componentElement
3566: .getSensitiveTemplateCategories(),
3567: categoryManager);
3568: Set sensitiveContentCategories = ComponentImport
3569: .sensitiveCategoriesFromXML(componentElement
3570: .getSensitiveContentCategories(),
3571: categoryManager);
3572: context.setIsFinal(isFinal);
3573: context.setComposedBlueprintName(composedBlueprint);
3574: if (acl != null) {
3575: context.setACL(acl);
3576: }
3577: context.setComponent(component);
3578:
3579: context
3580: .setSensitiveContentCategories(sensitiveContentCategories);
3581: context
3582: .setSensitiveTemplateCategories(sensitiveTemplateCategories);
3583:
3584: if (component instanceof FileFacade) {
3585: log
3586: .debug("'"
3587: + this .name
3588: + "':updateComponent() - ... updating FileFacade '"
3589: + component + "'");
3590: Iterator resources = contentResourceElements.iterator();
3591: while (resources.hasNext()) {
3592: ResourceElement resourceElement = (ResourceElement) resources
3593: .next();
3594: if (resourceElement.isBinary()) {
3595: resources.remove(); // remove this resource so it is not
3596: // streamed into database
3597: String extension = resourceElement
3598: .getExtension();
3599: properties.put("contentType", resourceElement
3600: .getContentType());
3601: properties.put("extension", extension);
3602: String source = resourceElement.getSrc();
3603: FileItem sourceFile = callData
3604: .getFileItem(source);
3605: if (sourceFile == null) {
3606: log
3607: .error("'"
3608: + this .name
3609: + "':updateComponent() - can not find file for FileFacade '"
3610: + component
3611: + "' and source '" + source
3612: + "'!");
3613: throw new ContelligentException(
3614: "Can not find file for FileFacade '"
3615: + component + "' source '"
3616: + source + "'!");
3617: }
3618: InputStream in = sourceFile.getInputStream();
3619: try {
3620: StringBuffer fileName = new StringBuffer(
3621: context.getPath().toPath());
3622: if (extension != null
3623: && extension.length() > 0) {
3624: fileName.append('.').append(extension);
3625: }
3626: getFileAdapter().storeResourceFromStream(
3627: fileName.toString(), in);
3628: } finally {
3629: in.close();
3630: in = null;
3631: }
3632: }
3633: }
3634: }
3635:
3636: Map changedResources;
3637: Iterator iterator = null;
3638:
3639: changedResources = createResources(contentResourceElements,
3640: sensitiveContentCategories, callData);
3641:
3642: iterator = changedResources.entrySet().iterator();
3643: while (iterator.hasNext()) {
3644: Map.Entry entry = (Map.Entry) iterator.next();
3645: if (entry.getValue() instanceof Resource) {
3646: context.setContentResource((String) entry.getKey(),
3647: (Resource) entry.getValue());
3648: } else {
3649: context.removeContentResource((String) entry
3650: .getKey());
3651: }
3652: }
3653:
3654: changedResources = createResources(
3655: templateResourceElements,
3656: sensitiveTemplateCategories, callData);
3657:
3658: iterator = changedResources.entrySet().iterator();
3659: while (iterator.hasNext()) {
3660: Map.Entry entry = (Map.Entry) iterator.next();
3661: if (entry.getValue() instanceof Resource) {
3662: context.setTemplateResource(
3663: (String) entry.getKey(), (Resource) entry
3664: .getValue());
3665: } else {
3666: context.removeTemplateResource((String) entry
3667: .getKey());
3668: }
3669: }
3670:
3671: if (!properties.isEmpty()) {
3672: context.getType().setProperties(
3673: component,
3674: context.getType().getProperties(properties,
3675: false));
3676: }
3677:
3678: ComponentPath path = new ComponentPath(pathName);
3679:
3680: context.setModifiedBy(callData.getContelligentSession()
3681: .getUser());
3682:
3683: if (isRoot() || componentExists(path, false)
3684: || componentAdapter.deleted(path)
3685: || checkDeleted(path)) {
3686: updateWrapper(context);
3687: } else {
3688: context.setPersistenceManager(this );
3689: componentAdapter.create(context);
3690: }
3691: relationsManager.updateRelations(component, ThreadedMem
3692: .getCallData(), false);
3693: if (!isImport()) {
3694: checkRelationsOfComponent(path, false, callData);
3695: }
3696: } catch (UnknownTypeException ute) {
3697: throw new ContelligentException("Type '" + typeName
3698: + "' could not be retrieved.", ute);
3699: } catch (TypeException te) {
3700: throw new ContelligentException(
3701: ContelligentExceptionID.persistence_propertyNotSet,
3702: te);
3703: } catch (CategoryException ce) {
3704: throw new ContelligentException(
3705: "Sensitive categories could not be converted.", ce);
3706: } catch (IOException e) {
3707: throw new ContelligentException(
3708: "Could not read resource content.", e);
3709: }
3710: }
3711:
3712: final public void createComponent(
3713: ComponentElement componentElement, CallData callData)
3714: throws ContelligentException {
3715: ComponentPath componentPath = getComponentPath(componentElement);
3716:
3717: if (componentExists(componentPath)) {
3718: throw new ComponentAlreadyExistsException(componentPath);
3719: }
3720:
3721: Component component = getComponent(componentPath.parentPath(),
3722: callData);
3723:
3724: if (!(component instanceof Container)) {
3725: throw new ContelligentException(
3726: ContelligentExceptionID.component_noContainer,
3727: new Object[] { componentPath.parentPath().toPath() });
3728: }
3729: Container parent = (Container) component;
3730: String typeName = componentElement.getType();
3731:
3732: ComponentMetainfoElement metainfoElement = componentElement
3733: .getMetainfoElement();
3734: ComponentSecurityElement securityElement = metainfoElement
3735: .getSecurityElement();
3736: AccessControlList acl = null;
3737: Type type = componentFactory.getType(typeName); // throws
3738: // UnknownTypeException
3739: Map properties = ComponentImport
3740: .createPropertyMapFromXML(componentElement);
3741: Metadata metadata = component.getComponentContext()
3742: .getMetadata();
3743: ComponentImport.loadMetadataFromXML(componentElement, metadata);
3744:
3745: if (securityElement != null) {
3746: acl = ComponentImport.createACLfromXML(componentPath
3747: .toPath(), securityElement, this );
3748: }
3749: // use converted property-map:
3750: Component answer = createComponent(parent, componentPath
3751: .getName(), type,
3752: type.getProperties(properties, false), acl, false,
3753: false, callData);
3754: // no postCreate(), no update of relations
3755: updateComponent(answer, componentElement, callData);
3756: String name = ComponentImport.loadBasicPublisherFromXML(
3757: componentElement, componentPath);
3758: if (name.length() > 0) {
3759: ComponentDBAdapter adapter = (ComponentDBAdapter) getComponentPersistenceAdapter();
3760: adapter.certifyComponentBasic(name, componentPath, false);
3761: }
3762: }
3763:
3764: final protected ComponentPath getComponentPath(
3765: ComponentElement componentElement) {
3766: return new ComponentPath(componentElement.getDir()
3767: + componentElement.getName());
3768: }
3769:
3770: final private Map createResources(Collection resourceElements,
3771: Collection sensitiveCategories, CallData callData)
3772: throws IOException, ContelligentException {
3773: Map resources = new HashMap();
3774: CategoryManager categoryManager = contelligent
3775: .getCategoryManager();
3776: long currentTime = TimeService.getInstance()
3777: .currentTimeMillis();
3778:
3779: for (Iterator i = resourceElements.iterator(); i.hasNext();) {
3780: ResourceElement resourceElement = (ResourceElement) i
3781: .next();
3782: Map supportedCategories = resourceElement
3783: .getSupportedCategories();
3784: boolean isResourceAccessible = true;
3785: for (Iterator j = sensitiveCategories.iterator(); j
3786: .hasNext();) {
3787: CategorySubset css = (CategorySubset) j.next();
3788: if (!supportedCategories.containsKey(css.getName())) {
3789: // Found a sensitive category name which is not supported by
3790: // this resource
3791: isResourceAccessible = false;
3792: } else {
3793: String[] sensitiveValues = css.getSupportedValues();
3794: boolean found = false;
3795: String supportedValue = (String) supportedCategories
3796: .get(css.getName());
3797: for (int k = 0; k < sensitiveValues.length; k++) {
3798: if (supportedValue.equals(sensitiveValues[k])) {
3799: found = true;
3800: }
3801: }
3802: if (!found) {
3803: // Found a supported category value which is not a valid
3804: // sensitive value (Yes, this is supposed to be checked
3805: // the other way around than the category name check
3806: // above)
3807: isResourceAccessible = false;
3808: }
3809: }
3810: }
3811: if (isResourceAccessible) {
3812: // Only add the resource if the supported categories on the
3813: // resource would result in the resource being accessible from
3814: // the sensitive category declared on the component level.
3815: String categoryIdentifier = categoryManager
3816: .createUniqueCategoryIdentifier(
3817: sensitiveCategories,
3818: supportedCategories);
3819: String contentType = resourceElement.getContentType();
3820: String extension = resourceElement.getExtension();
3821: String source = resourceElement.getSrc();
3822: String data = resourceElement.getData();
3823: String constraints = resourceElement.getConstraints();
3824: Resource resource = null;
3825:
3826: if (resourceElement.isBinary()) {
3827: InputStream in = null;
3828: long length = 0L;
3829:
3830: FileItem item = callData.getFileItem(source);
3831:
3832: if (item == null) {
3833: in = getFileAdapter().getResourceAsStream(
3834: source);
3835: length = getFileAdapter()
3836: .getResourceStreamLength(source);
3837: } else {
3838: in = item.getInputStream();
3839: length = item.getSize();
3840: }
3841:
3842: resource = new BinaryResource(in, contentType,
3843: extension, currentTime, (int) length);
3844: } else if (resourceElement.isNumber()) {
3845: Number number = new BigDecimal(data);
3846:
3847: resource = new NumberResource(number, currentTime);
3848: } else if (resourceElement.isText()) {
3849: if (source != null) {
3850: InputStream in = null;
3851: long length = 0L;
3852:
3853: FileItem item = callData.getFileItem(source);
3854:
3855: if (item == null) {
3856: in = getFileAdapter().getResourceAsStream(
3857: source);
3858: } else {
3859: in = item.getInputStream();
3860: }
3861:
3862: resource = new TextResource(in, currentTime);
3863: } else {
3864: resource = new TextResource(data, currentTime);
3865: }
3866: } else if (resourceElement.isString()) {
3867: resource = new StringResource(data, currentTime);
3868: } else if (resourceElement.isInvalidated()) {
3869: resource = null;
3870: } else {
3871: // The resource type is unknown.
3872: throw new ContelligentException(
3873: "Unknown resource type");
3874: }
3875: if (resource != null) {
3876: resource.setConstraints(constraints);
3877: resources.put(categoryIdentifier, resource);
3878: } else {
3879: // Dummy value to force deletion of invalidated resources
3880: // from the database.
3881: resources.put(categoryIdentifier, "");
3882: }
3883: } else {
3884: // Dummy value to force deletion of invalidated resources
3885: // from the database.
3886: String categoryIdentifier = categoryManager
3887: .createUniqueCategoryIdentifier(
3888: sensitiveCategories,
3889: supportedCategories);
3890: resources.put(categoryIdentifier, "");
3891: }
3892: }
3893: return resources;
3894: }
3895:
3896: /**
3897: * Implementation of {@link ComponentManager#isInstanceOf}.
3898: */
3899: final public boolean isInstanceOf(Component component,
3900: String typeName) {
3901: Type type = component.getComponentContext().getType();
3902: if (type.getName().equals(typeName)) {
3903: return true;
3904: }
3905: return componentFactory.isSubType(type, typeName);
3906: }
3907:
3908: final protected boolean isInstanceOf(ComponentPath path,
3909: String typeName) throws ComponentPersistenceException {
3910: String type = componentAdapter.getTypeOfComponent(path);
3911: if (type.equals(typeName)) {
3912: return true;
3913: }
3914:
3915: return componentFactory.isSubType(componentFactory
3916: .getType(type), typeName);
3917: }
3918:
3919: final private User getSystemUser() {
3920: return ContelligentSecurityManager.getSystemUser();
3921: }
3922:
3923: public final void setComponentFinal(ComponentPath path,
3924: boolean finalFlag, CallData callData)
3925: throws ComponentNotFoundException,
3926: ModificationVetoException, ComponentPersistenceException,
3927: ComponentLockException {
3928: boolean locked = lockComponent(path, callData);
3929: try {
3930: Component component = cloneComponent(path, callData);
3931: ComponentContextImpl context = (ComponentContextImpl) component
3932: .getComponentContext();
3933:
3934: context.setIsFinal(finalFlag);
3935: context.setModifiedBy(callData.getContelligentSession()
3936: .getUser());
3937: updateWrapper(context);
3938: fireChangeEvent(component);
3939: } finally {
3940: if (locked) {
3941: unlockComponent(path, callData);
3942: }
3943: }
3944: }
3945:
3946: public void validateBlueprintTypes() throws TypeException {
3947: componentFactory.validateBlueprintTypes(this );
3948: }
3949:
3950: public Collection getDeletedComponents()
3951: throws ComponentPersistenceException {
3952: if (isRoot()) {
3953: return Collections.EMPTY_SET;
3954: }
3955: return componentAdapter.getDeletedComponents();
3956: }
3957:
3958: public Collection getModifiedComponents(
3959: boolean filterBlueprintSubComponents)
3960: throws ComponentPersistenceException {
3961: if (isRoot()) {
3962: return Collections.EMPTY_SET;
3963: }
3964: Collection answer = componentAdapter.getModifiedComponents();
3965: if (filterBlueprintSubComponents) {
3966: ComponentManager parentCM = getParent();
3967: Iterator iterator = componentAdapter
3968: .getNewOrModifiedBlueprintInstances().iterator();
3969:
3970: while (iterator.hasNext()) {
3971: ComponentPath componentPath = (ComponentPath) iterator
3972: .next();
3973:
3974: if (!parentCM.componentExists(componentPath)) {
3975: Iterator subcomponents = componentAdapter
3976: .getLocalComponentNames(componentPath)
3977: .iterator();
3978: while (subcomponents.hasNext()) {
3979: ComponentDBPathHolder pathHolder = (ComponentDBPathHolder) subcomponents
3980: .next();
3981: answer.remove(pathHolder.getPath());
3982: }
3983: answer.add(componentPath);
3984: }
3985: }
3986: }
3987: return answer;
3988: }
3989:
3990: /**
3991: * Use of this method is permitted for afterCompletion only!!!
3992: *
3993: * @param path
3994: */
3995: void invalidatePath(ComponentPath path, boolean includeSubtree) {
3996:
3997: }
3998:
3999: public void invalidateCache(ComponentPath path) {
4000: invalidatePath(path, true);
4001: }
4002:
4003: public SystemIndex getSystemIndex() {
4004: return systemIndex;
4005: }
4006:
4007: public void setSkipListener(boolean b) {
4008: if (listener == null) {
4009: return;
4010: }
4011: listener.setSkip(b);
4012: }
4013:
4014: public void invalidateTypes() {
4015: componentFactory.invalidateTypes();
4016: }
4017:
4018: public void setReadOnlyPaths(Set readOnlyPaths) {
4019: this .readOnlyPaths = new HashSet(readOnlyPaths);
4020: }
4021:
4022: final public void changeTypeOfBlueprintInstance(ComponentPath path,
4023: String typeName, CallData callData)
4024: throws ContelligentException, ComponentNotFoundException,
4025: ModificationVetoException {
4026: Component component = getComponent(path, callData);
4027: Type type = component.getComponentContext().getType();
4028:
4029: if (!type.isBlueprint()) {
4030: throw new ContelligentException(
4031: ContelligentExceptionID.component_morph_noBlueprint,
4032: new Object[] { path.toPath() });
4033: }
4034: Type newType = componentFactory.getType(typeName);
4035: if (!newType.isBlueprint()) {
4036: throw new ContelligentException(
4037: ContelligentExceptionID.component_morph_noBlueprintType,
4038: new Object[] { typeName, path.toPath() });
4039: }
4040: if (!getComponent(type.getBlueprintPath(), callData)
4041: .getComponentContext().getType().equals(
4042: getComponent(newType.getBlueprintPath(),
4043: callData).getComponentContext()
4044: .getType())) {
4045: throw new ContelligentException(
4046: ContelligentExceptionID.component_morph_incompatibleTypes,
4047: new Object[] { typeName, type.getName(),
4048: path.toPath() });
4049: }
4050:
4051: boolean locked = lockComponent(path, callData);
4052: try {
4053: Component clone = cloneComponent(component);
4054: ComponentContextImpl context = (ComponentContextImpl) clone
4055: .getComponentContext();
4056: context.setType(newType);
4057: context.setModifiedBy(callData.getContelligentSession()
4058: .getUser());
4059:
4060: if (isRoot() || componentExists(path, false)) {
4061: updateWrapper(context);
4062: } else {
4063: componentAdapter.create(context);
4064: }
4065: fireChangeEvent(clone);
4066: } finally {
4067: if (locked) {
4068: unlockComponent(path, callData);
4069: }
4070: }
4071: }
4072:
4073: final public void addToAllBlueprintInstances(ComponentPath path,
4074: CallData callData) throws ContelligentException {
4075: if (componentFactory.isBlueprintPath(path)) {
4076: return;
4077: }
4078: ComponentPath blueprintRootPath = path;
4079: while (!componentFactory.isBlueprintPath(blueprintRootPath)) {
4080: if (blueprintRootPath.isRoot()) {
4081: throw new ContelligentException(
4082: ContelligentExceptionID.component_not_in_blueprint,
4083: new Object[] { path.toPath() });
4084: }
4085: blueprintRootPath = blueprintRootPath.parentPath();
4086: }
4087: ComponentPath relative = path.toRelativePath(blueprintRootPath);
4088: String blueprintType = componentFactory.getBlueprintType(
4089: blueprintRootPath).getName();
4090: Collection instances = getInstancesOfType(
4091: ComponentPath.ROOT_PATH, blueprintType);
4092: Iterator iterator = instances.iterator();
4093:
4094: while (iterator.hasNext()) {
4095: ComponentPath instancePath = (ComponentPath) iterator
4096: .next();
4097: ComponentPath targetPath = instancePath.append(relative);
4098: try {
4099: copyComponentTree(callData, path, targetPath
4100: .parentPath(), targetPath.getName());
4101: } catch (ComponentAlreadyExistsException caee) {
4102: // Subcomponent already exists here, so we can just skip
4103: // over this instance
4104: }
4105: }
4106: }
4107:
4108: private ComponentPath getReadOnlyRoot(ComponentPath path) {
4109: Iterator iterator = readOnlyPaths.iterator();
4110: while (iterator.hasNext()) {
4111: ComponentPath componentPath = (ComponentPath) iterator
4112: .next();
4113:
4114: if (path.isSubPathOf(componentPath)
4115: || path.equals(componentPath)) {
4116: return componentPath;
4117: }
4118: }
4119: return null;
4120: }
4121:
4122: protected void checkContainsReadOnly(final ComponentPath path) {
4123: checkReadOnly(path);
4124: Iterator iterator = readOnlyPaths.iterator();
4125: while (iterator.hasNext()) {
4126: ComponentPath componentPath = (ComponentPath) iterator
4127: .next();
4128: if (componentPath.isSubPathOf(path)) {
4129: throw new ContelligentSecurityException(
4130: ContelligentExceptionID.security_readOnly,
4131: new Object[] { componentPath });
4132: }
4133: }
4134: }
4135:
4136: public boolean isReadOnly(ComponentPath path) {
4137: try {
4138: checkReadOnly(path);
4139: } catch (ContelligentSecurityException cse) {
4140: return true;
4141: }
4142: return false;
4143: }
4144:
4145: public boolean containsReadOnly(ComponentPath path) {
4146: try {
4147: checkContainsReadOnly(path);
4148: } catch (ContelligentSecurityException cse) {
4149: return true;
4150: }
4151: return false;
4152: }
4153:
4154: final public void cleanUpBlueprintInstances(ComponentPath path,
4155: CallData callData) throws ContelligentException {
4156: Collection blueprintInstances;
4157: Component blueprint;
4158:
4159: if (componentFactory.isBlueprintPath(path)) {
4160: blueprintInstances = getInstancesOfType(
4161: ComponentPath.ROOT_PATH, componentFactory
4162: .getBlueprintType(path).getName());
4163: blueprint = getComponent(path, callData);
4164: } else {
4165: Component comp = getComponent(path, callData);
4166: Type type = comp.getComponentContext().getType();
4167:
4168: if (!type.isBlueprint()) {
4169: throw new ContelligentException(
4170: ContelligentExceptionID.component_no_blueprint_instance,
4171: new Object[] { path.toPath() });
4172: }
4173: blueprint = getComponent(type.getBlueprintPath(), callData);
4174: blueprintInstances = new ArrayList(1);
4175: blueprintInstances.add(path);
4176: }
4177: Set relativeBlueprintSubcomponents = new HashSet();
4178: ComponentPath blueprintPath = blueprint.getComponentContext()
4179: .getPath();
4180: Iterator iterator = componentAdapter.getAllSubComponentPaths(
4181: blueprintPath).iterator();
4182:
4183: while (iterator.hasNext()) {
4184: ComponentPath componentPath = new ComponentPath(
4185: (String) iterator.next());
4186: relativeBlueprintSubcomponents.add(componentPath
4187: .toRelativePath(blueprintPath));
4188: }
4189:
4190: Iterator instances = blueprintInstances.iterator();
4191:
4192: while (instances.hasNext()) {
4193: ComponentPath instancePath = (ComponentPath) instances
4194: .next();
4195: // Only check direct children of the instance
4196: Iterator subcomponents = getSubcomponentNames(
4197: (Container) getComponent(instancePath, callData))
4198: .iterator();
4199:
4200: while (subcomponents.hasNext()) {
4201: ComponentPath subComponentPath = instancePath
4202: .append((String) subcomponents.next());
4203: ComponentPath relative = subComponentPath
4204: .toRelativePath(instancePath);
4205: if (!relativeBlueprintSubcomponents.contains(relative)) {
4206: if (componentExists(subComponentPath)) {
4207: deleteComponentTree(callData, subComponentPath);
4208: }
4209: }
4210: }
4211: }
4212: }
4213:
4214: protected void checkReadOnly(final ComponentPath path) {
4215: ComponentPath readOnlyRoot = getReadOnlyRoot(path);
4216:
4217: if (readOnlyRoot != null) {
4218: throw new ContelligentSecurityException(
4219: ContelligentExceptionID.security_readOnly,
4220: new Object[] { readOnlyRoot });
4221: }
4222: }
4223:
4224: ComponentFactory getComponentFactory() {
4225: return componentFactory;
4226: }
4227:
4228: /*
4229: * (non-Javadoc)
4230: *
4231: * @see de.finix.contelligent.ComponentManager#getTypesInSubTree(de.finix.contelligent.ComponentPath)
4232: */
4233: public Collection getTypesInSubTree(ComponentPath topMostPath)
4234: throws ComponentSystemException {
4235: ComponentPersistenceAdapter adapter = getComponentPersistenceAdapter();
4236: Set typeSet = new HashSet();
4237: try {
4238: Collection typeNameList = adapter
4239: .getTypeNamesInSubTree(topMostPath);
4240: Iterator i = typeNameList.iterator();
4241:
4242: while (i.hasNext()) {
4243: String typeName = (String) i.next();
4244: Type type = componentFactory.getType(typeName);
4245: typeSet.add(type);
4246: }
4247: } catch (ComponentPersistenceException e) {
4248: Object info[] = new Object[] { topMostPath.toPath() };
4249: ComponentSystemException e1 = new ComponentSystemException(
4250: ContelligentExceptionID.type_fromSubtree, info, e);
4251: throw e1;
4252: }
4253: return typeSet;
4254: }
4255:
4256: public List selectMetaContent(Component root,
4257: ComponentPath relative, String key, String value,
4258: String comparator) throws ComponentPersistenceException {
4259: ComponentDBAdapter adapter = (ComponentDBAdapter) getComponentPersistenceAdapter();
4260: return adapter.selectMetaContent(root, relative, key, value,
4261: comparator);
4262: }
4263:
4264: public List selectComponentsByName(Component root, String name)
4265: throws ComponentPersistenceException {
4266: ComponentDBAdapter adapter = (ComponentDBAdapter) getComponentPersistenceAdapter();
4267: return adapter.selectComponentsByName(root, name);
4268: }
4269:
4270: public long getSubtreeSize(Component subTree)
4271: throws ComponentPersistenceException {
4272: ComponentDBAdapter adapter = (ComponentDBAdapter) getComponentPersistenceAdapter();
4273: return adapter.getSubtreeSize((ComponentContextImpl) subTree
4274: .getComponentContext());
4275: }
4276:
4277: public long getSubtreeComponents(Component subTree)
4278: throws ComponentPersistenceException {
4279: ComponentDBAdapter adapter = (ComponentDBAdapter) getComponentPersistenceAdapter();
4280: return adapter
4281: .getSubtreeComponents((ComponentContextImpl) subTree
4282: .getComponentContext());
4283: }
4284:
4285: public void certifyComponent(String name, String key, int type,
4286: boolean subTree, ComponentPath path, CallData callData)
4287: throws NoWritePermissionException,
4288: ComponentNotFoundException {
4289: Component component = getComponent(path, callData);
4290: final ContelligentPrincipal caller = callData
4291: .getContelligentSession().getUser();
4292: if (!callerHasPermission(caller, callData, component,
4293: ComponentPermission.WRITE)) {
4294: log.warn("'" + this .name
4295: + "':certifyComponent() - caller '" + caller
4296: + "' has no write access for component '"
4297: + component + "'!");
4298: throw new NoWritePermissionException(caller, component
4299: .getComponentContext().getPath());
4300: }
4301: ComponentDBAdapter adapter = (ComponentDBAdapter) getComponentPersistenceAdapter();
4302: if (type == CERT_BASIC) {
4303: try {
4304: String hashText = "[c1contell19]" + name;
4305: if (!key.equals(StringHash.getHash(hashText))) {
4306: // Invalid key
4307: throw new ContelligentRuntimeException(
4308: "Invalid data.");
4309: }
4310: log.info("Begin cert now...");
4311: adapter.certifyComponentBasic(name, path, subTree);
4312: invalidateCache(path);
4313: addEvent(new ComponentEvent(ComponentEvent.CHANGE,
4314: path, getName()));
4315: log.info("Cert successful!");
4316: } catch (Exception e) {
4317: throw new ContelligentRuntimeException(
4318: "Certification failed.", e);
4319: }
4320: } else if (type == CERT_USER) {
4321: try {
4322: adapter.certifyComponentUser(
4323: caller.toPrincipalString(), path, subTree);
4324: invalidateCache(path);
4325: addEvent(new ComponentEvent(ComponentEvent.CHANGE,
4326: path, getName()));
4327: } catch (Exception e) {
4328: throw new ContelligentRuntimeException(
4329: "Signing failed.", e);
4330: }
4331: } else {
4332: // TODO: Add "signed" cert type
4333: throw new ContelligentRuntimeException(
4334: "Unsupported certification type.");
4335: }
4336: }
4337:
4338: public int getMaxCacheSize() {
4339: return 0;
4340: }
4341:
4342: public void setMaxCacheSize(int maxSize) {
4343: }
4344:
4345: public int getActualCacheSize() {
4346: return 0;
4347: }
4348:
4349: public long getCacheCalls() {
4350: return 0;
4351: }
4352:
4353: public long getCacheMisses() {
4354: return 0;
4355: }
4356:
4357: /**
4358: * Wraps componentAdapter.update() call so that subclasses can do
4359: * centralized error handling for this call.
4360: */
4361: protected void updateWrapper(ComponentContextImpl ctx)
4362: throws ComponentPersistenceException {
4363: componentAdapter.update(ctx);
4364: }
4365:
4366: /**
4367: * @return
4368: */
4369: public SystemIndexer getSystemIndexer() {
4370: return this.listener;
4371: }
4372: }
|