/* * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.jcr.impl.core.nodetype; import org.exoplatform.services.jcr.access.AccessControlEntry; import org.exoplatform.services.jcr.core.nodetype.NodeDefinitionData; import org.exoplatform.services.jcr.core.nodetype.NodeTypeData; import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager; import org.exoplatform.services.jcr.core.nodetype.PropertyDefinitionData; import org.exoplatform.services.jcr.dataflow.ItemDataConsumer; import org.exoplatform.services.jcr.dataflow.ItemState; import org.exoplatform.services.jcr.dataflow.PlainChangesLog; import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl; import org.exoplatform.services.jcr.datamodel.InternalQName; import org.exoplatform.services.jcr.datamodel.ItemData; import org.exoplatform.services.jcr.datamodel.ItemType; import org.exoplatform.services.jcr.datamodel.NodeData; import org.exoplatform.services.jcr.datamodel.QPathEntry; import org.exoplatform.services.jcr.datamodel.ValueData; import org.exoplatform.services.jcr.impl.Constants; import org.exoplatform.services.jcr.impl.core.value.BaseValue; import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData; import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData; import org.exoplatform.services.jcr.impl.dataflow.TransientValueData; import org.exoplatform.services.jcr.impl.dataflow.version.VersionHistoryDataHelper; import org.exoplatform.services.jcr.util.IdGenerator; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.util.ArrayList; import java.util.Calendar; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.ValueFactory; /** * @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a> * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $ * */ public class ItemAutocreator { private static final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.ItemAutocreator"); private final NodeTypeDataManager nodeTypeDataManager; private final ItemDataConsumer dataConsumer; private final ValueFactory valueFactory; private final boolean avoidCheckExistedChildItems; /** * @param nodeTypeDataManager */ public ItemAutocreator(NodeTypeDataManager nodeTypeDataManager, ValueFactory valueFactory, ItemDataConsumer dataConsumer, boolean avoidCheckExistedChildItems) { super(); this.nodeTypeDataManager = nodeTypeDataManager; this.valueFactory = valueFactory; this.dataConsumer = dataConsumer; this.avoidCheckExistedChildItems = avoidCheckExistedChildItems; } public PlainChangesLog makeAutoCreatedItems(final NodeData parent, final InternalQName nodeTypeName, final ItemDataConsumer targetDataManager, final String owner) throws RepositoryException { return makeAutoCreatedItems(parent, nodeTypeName, targetDataManager, owner, false); } /** * Prepares changes log */ private PlainChangesLog makeAutoCreatedItems(final NodeData parent, final InternalQName nodeTypeName, final ItemDataConsumer targetDataManager, final String owner, boolean addedAutoCreatedNodes) throws RepositoryException { final PlainChangesLogImpl changes = new PlainChangesLogImpl(); final NodeTypeData type = nodeTypeDataManager.getNodeType(nodeTypeName); changes.addAll(makeAutoCreatedProperties(parent, nodeTypeName, nodeTypeDataManager.getAllPropertyDefinitions(nodeTypeName), targetDataManager, owner).getAllStates()); // Add autocreated child nodes changes.addAll(makeAutoCreatedNodes(parent, nodeTypeName, nodeTypeDataManager.getAllChildNodeDefinitions(nodeTypeName), targetDataManager, owner).getAllStates()); // versionable if (nodeTypeDataManager.isNodeType(Constants.MIX_VERSIONABLE, new InternalQName[]{type.getName()})) { // using VH helper as for one new VH, all changes in changes log changes.addAll(makeMixVesionableChanges(parent).getAllStates()); } return changes; } public PlainChangesLog makeAutoCreatedNodes(final NodeData parent, final InternalQName typeName, final NodeDefinitionData[] nodeDefs, final ItemDataConsumer targetDataManager, final String owner) throws RepositoryException { return makeAutoCreatedNodes(parent, typeName, nodeDefs, targetDataManager, owner, false); } private PlainChangesLog makeAutoCreatedNodes(final NodeData parent, final InternalQName typeName, final NodeDefinitionData[] nodeDefs, final ItemDataConsumer targetDataManager, final String owner, boolean addedAutoCreatedNodes) throws RepositoryException { final PlainChangesLogImpl changes = new PlainChangesLogImpl(); final Set<InternalQName> addedNodes = new HashSet<InternalQName>(); for (final NodeDefinitionData ndef : nodeDefs) { if (ndef.isAutoCreated()) { final ItemData pdata = avoidCheckExistedChildItems ? null : targetDataManager.getItemData(parent, new QPathEntry( ndef.getName(), 0), ItemType.NODE, false); if (pdata == null && !addedNodes.contains(ndef.getName()) || pdata != null && !pdata.isNode()) { final TransientNodeData childNodeData = TransientNodeData.createNodeData(parent, ndef.getName(), ndef.getDefaultPrimaryType(), IdGenerator.generate()); if (!addedAutoCreatedNodes) { addedAutoCreatedNodes = true; changes.add(ItemState.createAddedAutoCreatedNodes(parent)); } changes.add(ItemState.createAddedState(childNodeData, false)); changes.addAll(makeAutoCreatedItems(childNodeData, childNodeData.getPrimaryTypeName(), targetDataManager, owner, addedAutoCreatedNodes).getAllStates()); addedNodes.add(ndef.getName()); } else { if (this.LOG.isDebugEnabled()) { this.LOG.debug("Skipping existed node " + ndef.getName() + " in " + parent.getQPath().getAsString() + " during the automatic creation of items for " + typeName.getAsString() + " nodetype or mixin type"); } } } } return changes; } public PlainChangesLog makeAutoCreatedProperties(final NodeData parent, final InternalQName typeName, final PropertyDefinitionData[] propDefs, final ItemDataConsumer targetDataManager, final String owner) throws RepositoryException { final PlainChangesLogImpl changes = new PlainChangesLogImpl(); final Set<InternalQName> addedProperties = new HashSet<InternalQName>(); // Add autocreated child properties for (final PropertyDefinitionData pdef : propDefs) { if (pdef.isAutoCreated()) { final ItemData pdata = avoidCheckExistedChildItems ? null : targetDataManager.getItemData(parent, new QPathEntry( pdef.getName(), 0), ItemType.PROPERTY, false); if (pdata == null && !addedProperties.contains(pdef.getName()) || pdata != null && pdata.isNode()) { final List<ValueData> listAutoCreateValue = autoCreatedValue(parent, typeName, pdef, owner); if (listAutoCreateValue != null) { final TransientPropertyData propertyData = TransientPropertyData.createPropertyData(parent, pdef.getName(), pdef.getRequiredType(), pdef.isMultiple(), listAutoCreateValue); changes.add(ItemState.createAddedState(propertyData)); addedProperties.add(pdef.getName()); } } else { if (this.LOG.isDebugEnabled()) { this.LOG.debug("Skipping existed property " + pdef.getName() + " in " + parent.getQPath().getAsString() + " during the automatic creation of items for " + typeName.getAsString() + " nodetype or mixin type"); } } } } return changes; } /** * @param parent * @return * @throws RepositoryException */ public PlainChangesLog makeMixVesionableChanges(final NodeData parent) throws RepositoryException { PlainChangesLog changesLog = new PlainChangesLogImpl(); new VersionHistoryDataHelper(parent, changesLog, dataConsumer, nodeTypeDataManager); return changesLog; } protected List<ValueData> autoCreatedValue(final NodeData parent, final InternalQName typeName, final PropertyDefinitionData def, final String owner) throws RepositoryException { final List<ValueData> vals = new ArrayList<ValueData>(); if (nodeTypeDataManager.isNodeType(Constants.NT_BASE, new InternalQName[]{typeName}) && def.getName().equals(Constants.JCR_PRIMARYTYPE)) { vals.add(new TransientValueData(parent.getPrimaryTypeName())); } else if (nodeTypeDataManager.isNodeType(Constants.MIX_REFERENCEABLE, new InternalQName[]{typeName}) && def.getName().equals(Constants.JCR_UUID)) { vals.add(new TransientValueData(parent.getIdentifier())); } else if (nodeTypeDataManager.isNodeType(Constants.NT_HIERARCHYNODE, new InternalQName[]{typeName}) && def.getName().equals(Constants.JCR_CREATED)) { vals.add(new TransientValueData(Calendar.getInstance())); } else if (nodeTypeDataManager.isNodeType(Constants.NT_HIERARCHYNODE, new InternalQName[]{typeName}) && def.getName().equals(new InternalQName(Constants.NS_JCR_URI, "createdBy"))) { vals.add(new TransientValueData(owner)); } else if (nodeTypeDataManager.isNodeType(Constants.EXO_OWNEABLE, new InternalQName[]{typeName}) && def.getName().equals(Constants.EXO_OWNER)) { // String owner = session.getUserID(); vals.add(new TransientValueData(owner)); } else if (nodeTypeDataManager.isNodeType(Constants.EXO_PRIVILEGEABLE, new InternalQName[]{typeName}) && def.getName().equals(Constants.EXO_PERMISSIONS)) { for (final AccessControlEntry ace : parent.getACL().getPermissionEntries()) { vals.add(new TransientValueData(ace)); } } else { final String[] propVal = def.getDefaultValues(); // there can be null in definition but should not be null value if (propVal != null && propVal.length != 0) { for (final String v : propVal) { if (v != null) { if (def.getRequiredType() == PropertyType.UNDEFINED) { vals.add(((BaseValue)this.valueFactory.createValue(v)).getInternalData()); } else { vals.add(((BaseValue)this.valueFactory.createValue(v, def.getRequiredType())).getInternalData()); } } else { vals.add(null); } } } else { return null; } } return vals; } }