/* * 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; import org.exoplatform.services.jcr.access.AccessControlEntry; import org.exoplatform.services.jcr.access.AccessControlList; import org.exoplatform.services.jcr.access.AccessControlPolicy; import org.exoplatform.services.jcr.access.PermissionType; import org.exoplatform.services.jcr.config.RepositoryConfigurationException; import org.exoplatform.services.jcr.config.RepositoryEntry; import org.exoplatform.services.jcr.config.WorkspaceEntry; import org.exoplatform.services.jcr.core.ExtendedPropertyType; import org.exoplatform.services.jcr.dataflow.DataManager; 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.dataflow.TransactionChangesLog; import org.exoplatform.services.jcr.datamodel.InternalQName; import org.exoplatform.services.jcr.datamodel.NodeData; import org.exoplatform.services.jcr.datamodel.QPath; import org.exoplatform.services.jcr.datamodel.ValueData; import org.exoplatform.services.jcr.impl.Constants; 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.persistent.CacheableWorkspaceDataManager; import org.exoplatform.services.jcr.util.IdGenerator; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.security.IdentityConstants; import java.util.ArrayList; import java.util.List; import javax.jcr.PathNotFoundException; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; /** * Created by The eXo Platform SAS. <br> Default workspace intializer. <br> * Can be configured with root-nodetype and root-permissions parameters. If * root-nodetype and root-permissions are empty then <br> root-nodetype = * nt:unstructured <br> root-permissions = ACL default <br> values will be * applied. * * @author Gennady Azarenkov * @version $Id: ScratchWorkspaceInitializer.java 13986 2008-05-08 10:48:43Z * pnedonosko $ */ public class ScratchWorkspaceInitializer implements WorkspaceInitializer { protected static final Log log = ExoLogger.getLogger("exo.jcr.component.core.ScratchWorkspaceInitializer"); private final String systemWorkspaceName; private final String workspaceName; private final DataManager dataManager; private final String accessControlType; // private final NamespaceDataPersister nsPersister; private final String rootPermissions; private final InternalQName rootNodeType; public ScratchWorkspaceInitializer(WorkspaceEntry config, RepositoryEntry repConfig, CacheableWorkspaceDataManager dataManager, LocationFactory locationFactory) throws RepositoryConfigurationException, PathNotFoundException, RepositoryException { this.systemWorkspaceName = repConfig.getSystemWorkspaceName(); this.accessControlType = repConfig.getAccessControl(); this.workspaceName = config.getName(); // workspace root params String rootPermissions = null; String rootNodeType = null; if (config.getInitializer() != null) { // use user configuration for initializer rootPermissions = config.getInitializer().getParameterValue(WorkspaceInitializer.ROOT_PERMISSIONS_PARAMETER, null); rootNodeType = config.getInitializer().getParameterValue(WorkspaceInitializer.ROOT_NODETYPE_PARAMETER, null); } // default behaviour root-nodetype=nt:unstructured, root-permissions will be // managed by // AccessControlList class this.rootPermissions = rootPermissions; this.rootNodeType = rootNodeType != null ? locationFactory.parseJCRName(rootNodeType).getInternalName() : Constants.NT_UNSTRUCTURED; this.dataManager = dataManager; } public NodeData initWorkspace() throws RepositoryException { if (isWorkspaceInitialized()) { return (NodeData)dataManager.getItemData(Constants.ROOT_UUID); } NodeData root = initRootNode(rootNodeType); if (log.isDebugEnabled()) log.debug("Root node for " + workspaceName + " initialized. NodeType: " + rootNodeType + " system workspace: " + systemWorkspaceName); // Init system workspace if (workspaceName.equals(systemWorkspaceName)) { // initialize /jcr:system NodeData sys = initJcrSystemNode(root); } return root; } /** * Workspace jobs. Will start after the repository initialization. */ public void start() { } public boolean isWorkspaceInitialized() throws RepositoryException { try { return dataManager.getItemData(Constants.ROOT_UUID) != null; } catch (RepositoryException e) { throw new RepositoryException("Cannot check if the workspace '" + workspaceName + "' has already been initialized", e); } } private NodeData initRootNode(InternalQName rootNodeType) throws RepositoryException { boolean addACL = !accessControlType.equals(AccessControlPolicy.DISABLE); PlainChangesLog changesLog = new PlainChangesLogImpl(); TransientNodeData rootNode; if (addACL) { AccessControlList acl = new AccessControlList(); if (rootPermissions != null) { acl.removePermissions(IdentityConstants.ANY); acl.addPermissions(rootPermissions); } InternalQName[] mixins = new InternalQName[]{Constants.EXO_OWNEABLE, Constants.EXO_PRIVILEGEABLE}; rootNode = new TransientNodeData(Constants.ROOT_PATH, Constants.ROOT_UUID, -1, rootNodeType, mixins, 0, null, acl); changesLog.add(new ItemState(rootNode, ItemState.ADDED, false, null)); TransientPropertyData primaryType = new TransientPropertyData(QPath.makeChildPath(rootNode.getQPath(), Constants.JCR_PRIMARYTYPE), IdGenerator .generate(), -1, PropertyType.NAME, rootNode.getIdentifier(), false, new TransientValueData(rootNodeType)); changesLog.add(new ItemState(primaryType, ItemState.ADDED, false, null)); // // jcr:mixinTypes List<ValueData> mixValues = new ArrayList<ValueData>(); for (InternalQName mixin : mixins) { mixValues.add(new TransientValueData(mixin)); } TransientPropertyData exoMixinTypes = TransientPropertyData.createPropertyData(rootNode, Constants.JCR_MIXINTYPES, PropertyType.NAME, true, mixValues); TransientPropertyData exoOwner = TransientPropertyData.createPropertyData(rootNode, Constants.EXO_OWNER, PropertyType.STRING, false, new TransientValueData(acl.getOwner())); List<ValueData> permsValues = new ArrayList<ValueData>(); for (int i = 0; i < acl.getPermissionEntries().size(); i++) { AccessControlEntry entry = acl.getPermissionEntries().get(i); permsValues.add(new TransientValueData(entry)); } TransientPropertyData exoPerms = TransientPropertyData.createPropertyData(rootNode, Constants.EXO_PERMISSIONS, ExtendedPropertyType.PERMISSION, true, permsValues); changesLog.add(ItemState.createAddedState(exoMixinTypes)).add(ItemState.createAddedState(exoOwner)).add( ItemState.createAddedState(exoPerms)); changesLog.add(new ItemState(rootNode, ItemState.MIXIN_CHANGED, false, null)); } else { rootNode = new TransientNodeData(Constants.ROOT_PATH, Constants.ROOT_UUID, -1, rootNodeType, new InternalQName[0], 0, null, new AccessControlList()); changesLog.add(new ItemState(rootNode, ItemState.ADDED, false, null)); TransientPropertyData primaryType = new TransientPropertyData(QPath.makeChildPath(rootNode.getQPath(), Constants.JCR_PRIMARYTYPE), IdGenerator .generate(), -1, PropertyType.NAME, rootNode.getIdentifier(), false, new TransientValueData(rootNodeType)); changesLog.add(new ItemState(primaryType, ItemState.ADDED, false, null)); // } dataManager.save(new TransactionChangesLog(changesLog)); return rootNode; } private NodeData initJcrSystemNode(NodeData root) throws RepositoryException { boolean addACL = !accessControlType.equals(AccessControlPolicy.DISABLE); PlainChangesLog changesLog = new PlainChangesLogImpl(); TransientNodeData jcrSystem; if (addACL) { InternalQName[] mixins = new InternalQName[]{Constants.EXO_OWNEABLE, Constants.EXO_PRIVILEGEABLE}; jcrSystem = TransientNodeData.createNodeData(root, Constants.JCR_SYSTEM, Constants.NT_UNSTRUCTURED, mixins, Constants.SYSTEM_UUID); AccessControlList acl = jcrSystem.getACL(); TransientPropertyData primaryType = TransientPropertyData.createPropertyData(jcrSystem, Constants.JCR_PRIMARYTYPE, PropertyType.NAME, false, new TransientValueData(jcrSystem.getPrimaryTypeName())); changesLog.add(ItemState.createAddedState(jcrSystem)).add(ItemState.createAddedState(primaryType)); // jcr:mixinTypes List<ValueData> mixValues = new ArrayList<ValueData>(); for (InternalQName mixin : mixins) { mixValues.add(new TransientValueData(mixin)); } TransientPropertyData exoMixinTypes = TransientPropertyData.createPropertyData(jcrSystem, Constants.JCR_MIXINTYPES, PropertyType.NAME, true, mixValues); TransientPropertyData exoOwner = TransientPropertyData.createPropertyData(jcrSystem, Constants.EXO_OWNER, PropertyType.STRING, false, new TransientValueData(acl.getOwner())); List<ValueData> permsValues = new ArrayList<ValueData>(); for (int i = 0; i < acl.getPermissionEntries().size(); i++) { AccessControlEntry entry = acl.getPermissionEntries().get(i); permsValues.add(new TransientValueData(entry)); } TransientPropertyData exoPerms = TransientPropertyData.createPropertyData(jcrSystem, Constants.EXO_PERMISSIONS, ExtendedPropertyType.PERMISSION, true, permsValues); changesLog.add(ItemState.createAddedState(exoMixinTypes)).add(ItemState.createAddedState(exoOwner)).add( ItemState.createAddedState(exoPerms)); changesLog.add(new ItemState(jcrSystem, ItemState.MIXIN_CHANGED, false, null)); } else { jcrSystem = TransientNodeData.createNodeData(root, Constants.JCR_SYSTEM, Constants.NT_UNSTRUCTURED, Constants.SYSTEM_UUID); TransientPropertyData primaryType = TransientPropertyData.createPropertyData(jcrSystem, Constants.JCR_PRIMARYTYPE, PropertyType.NAME, false, new TransientValueData(jcrSystem.getPrimaryTypeName())); changesLog.add(ItemState.createAddedState(jcrSystem)).add(ItemState.createAddedState(primaryType)); } // init version storage AccessControlList acl = new AccessControlList(); acl.removePermissions(IdentityConstants.ANY); acl.addPermissions(IdentityConstants.ANY, new String[]{PermissionType.READ}); for (AccessControlEntry entry : jcrSystem.getACL().getPermissionEntries()) { String identity = entry.getIdentity(); String permission = entry.getPermission(); if (!identity.equals(IdentityConstants.ANY) || !permission.equals(PermissionType.READ)) { acl.addPermissions(identity, new String[]{permission}); } } TransientNodeData versionStorageNodeData = TransientNodeData.createNodeData(jcrSystem, Constants.JCR_VERSIONSTORAGE, Constants.EXO_VERSIONSTORAGE, Constants.VERSIONSTORAGE_UUID, acl); TransientPropertyData vsPrimaryType = TransientPropertyData.createPropertyData(versionStorageNodeData, Constants.JCR_PRIMARYTYPE, PropertyType.NAME, false, new TransientValueData(versionStorageNodeData.getPrimaryTypeName())); TransientPropertyData exoMixinTypes = TransientPropertyData.createPropertyData(versionStorageNodeData, Constants.JCR_MIXINTYPES, PropertyType.NAME, true, new TransientValueData(Constants.EXO_PRIVILEGEABLE)); List<ValueData> permsValues = new ArrayList<ValueData>(); for (int i = 0; i < acl.getPermissionEntries().size(); i++) { AccessControlEntry entry = acl.getPermissionEntries().get(i); permsValues.add(new TransientValueData(entry)); } TransientPropertyData exoPerms = TransientPropertyData.createPropertyData(versionStorageNodeData, Constants.EXO_PERMISSIONS, ExtendedPropertyType.PERMISSION, true, permsValues); changesLog.add(ItemState.createAddedState(versionStorageNodeData)); changesLog.add(ItemState.createAddedState(vsPrimaryType)); changesLog.add(ItemState.createAddedState(exoMixinTypes)); changesLog.add(ItemState.createAddedState(exoPerms)); changesLog.add(new ItemState(versionStorageNodeData, ItemState.MIXIN_CHANGED, false, null)); dataManager.save(new TransactionChangesLog(changesLog)); return jcrSystem; } public void stop() { } }