/* * 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.config.RepositoryEntry; import org.exoplatform.services.jcr.core.ComponentPersister; 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.ItemData; import org.exoplatform.services.jcr.datamodel.ItemType; import org.exoplatform.services.jcr.datamodel.NodeData; import org.exoplatform.services.jcr.datamodel.PropertyData; 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.dataflow.TransientItemData; 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.ValueDataUtil; import org.exoplatform.services.jcr.impl.util.NodeDataReader; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; /** * Created by The eXo Platform SAS. * * @author <a href="mailto:gennady.azarenkov@exoplatform.com">Gennady * Azarenkov</a> * @version $Id: NamespaceDataPersister.java 13962 2008-05-07 16:00:48Z * pnedonosko $ */ public class NamespaceDataPersister implements ComponentPersister { public static Log log = ExoLogger.getLogger("exo.jcr.component.core.NamespaceDataPersister"); private final DataManager dataManager; private NodeData nsRoot; private final RepositoryEntry repConfig; private boolean started = false; public NamespaceDataPersister(DataManager dataManager, RepositoryEntry repConfig) throws RepositoryException { this.dataManager = dataManager; this.repConfig = repConfig; } /** * Add new namespace. * * @param prefix * NS prefix * @param uri * NS URI * @throws RepositoryException * Repository error */ public void addNamespace(String prefix, String uri) throws RepositoryException { if (!started) { if (log.isDebugEnabled()) log.debug("Unable save namespace " + uri + "=" + prefix + " in to the storage. Storage not initialized"); return; } PlainChangesLog changesLog = new PlainChangesLogImpl(); internallAdd(changesLog, prefix, uri); dataManager.save(new TransactionChangesLog(changesLog)); } private PlainChangesLog internallAdd(PlainChangesLog changesLog, String prefix, String uri) { TransientNodeData nsNode = TransientNodeData.createNodeData(nsRoot, new InternalQName("", prefix), Constants.EXO_NAMESPACE); TransientPropertyData primaryType = TransientPropertyData.createPropertyData(nsNode, Constants.JCR_PRIMARYTYPE, PropertyType.NAME, false, new TransientValueData(nsNode.getPrimaryTypeName())); TransientPropertyData exoUri = TransientPropertyData.createPropertyData(nsNode, Constants.EXO_URI_NAME, PropertyType.STRING, false, new TransientValueData(uri)); TransientPropertyData exoPrefix = TransientPropertyData.createPropertyData(nsNode, Constants.EXO_PREFIX, PropertyType.STRING, false, new TransientValueData(prefix)); changesLog.add(ItemState.createAddedState(nsNode)).add(ItemState.createAddedState(primaryType)).add( ItemState.createAddedState(exoUri)).add(ItemState.createAddedState(exoPrefix)); return changesLog; } /** * Add new namespace. * * @param namespaceMap * @throws RepositoryException Repository error */ public void addNamespaces(Map<String, String> namespaceMap) throws RepositoryException { if (!started) { log.warn("Unable save namespaces in to the storage. Storage not initialized"); return; } PlainChangesLog changesLog = new PlainChangesLogImpl(); for (Map.Entry<String, String> entry : namespaceMap.entrySet()) { String prefix = entry.getKey(); String uri = entry.getValue(); if (prefix != null) { if (log.isDebugEnabled()) log.debug("Namespace " + uri + ":" + prefix); internallAdd(changesLog, prefix, uri); } } dataManager.save(new TransactionChangesLog(changesLog)); } public boolean isStorageFilled() { try { List<NodeData> storageContent = dataManager.getChildNodesData(nsRoot); return storageContent.size() > 0; } catch (RepositoryException e) { log.error(e.getLocalizedMessage(), e); } return false; } public void removeNamespace(String prefix) throws RepositoryException { if (!started) { log.warn("Unable remove namspace " + prefix + " from the storage. Storage not initialized"); return; } PlainChangesLogImpl plainChangesLogImpl = new PlainChangesLogImpl(); ItemData prefData = dataManager.getItemData(nsRoot, new QPathEntry(new InternalQName("", prefix), 0), ItemType.NODE); if (prefData != null && prefData.isNode()) { List<PropertyData> childs = dataManager.getChildPropertiesData((NodeData)prefData); for (PropertyData propertyData : childs) { plainChangesLogImpl.add(ItemState.createDeletedState(copyPropertyData(propertyData), true)); } prefData = new TransientNodeData(prefData.getQPath(), prefData.getIdentifier(), prefData.getPersistedVersion(), ((NodeData)prefData).getPrimaryTypeName(), ((NodeData)prefData).getMixinTypeNames(), ((NodeData)prefData).getOrderNumber(), ((NodeData)prefData).getParentIdentifier(), ((NodeData)prefData) .getACL()); plainChangesLogImpl.add(ItemState.createDeletedState(prefData, true)); } dataManager.save(new TransactionChangesLog(plainChangesLogImpl)); } /** * {@inheritDoc} */ public void start() { if (!started) { try { NodeData jcrSystem = (NodeData)dataManager.getItemData(Constants.SYSTEM_UUID); if (jcrSystem != null) { NodeData exoNamespaces = (NodeData)dataManager.getItemData(jcrSystem, new QPathEntry(Constants.EXO_NAMESPACES, 1), ItemType.NODE); if (exoNamespaces == null) { initStorage(jcrSystem, !repConfig.getAccessControl().equals(AccessControlPolicy.DISABLE)); this.nsRoot = (NodeData)dataManager.getItemData(jcrSystem, new QPathEntry(Constants.EXO_NAMESPACES, 1), ItemType.NODE); } else { this.nsRoot = exoNamespaces; } } else { throw new RepositoryException("Nodetypes storage (/jcr:systemnode) is not initialized."); } } catch (RepositoryException e) { throw new RuntimeException(e.getLocalizedMessage(), e); } started = true; } } public void stop() { } void loadNamespaces(Map<String, String> namespacesMap, Map<String, String> urisMap) throws RepositoryException { if (!isInialized()) { NodeData jcrSystem = (NodeData)dataManager.getItemData(Constants.SYSTEM_UUID); if (jcrSystem != null) this.nsRoot = (NodeData)dataManager.getItemData(jcrSystem, new QPathEntry(Constants.EXO_NAMESPACES, 1), ItemType.NODE); else throw new RepositoryException( "/jcr:system is not found. Possible the workspace is not initialized properly"); } if (isInialized()) { NodeDataReader nsReader = new NodeDataReader(nsRoot, dataManager); nsReader.setRememberSkiped(true); nsReader.forNodesByType(Constants.EXO_NAMESPACE); nsReader.read(); List<NodeDataReader> nsData = nsReader.getNodesByType(Constants.EXO_NAMESPACE); for (NodeDataReader nsr : nsData) { nsr.forProperty(Constants.EXO_URI_NAME, PropertyType.STRING).forProperty(Constants.EXO_PREFIX, PropertyType.STRING); nsr.read(); String exoUri = ValueDataUtil.getString(nsr.getPropertyValue(Constants.EXO_URI_NAME)); String exoPrefix = ValueDataUtil.getString(nsr.getPropertyValue(Constants.EXO_PREFIX)); namespacesMap.put(exoPrefix, exoUri); urisMap.put(exoUri, exoPrefix); if (log.isDebugEnabled()) log.debug("Namespace " + exoPrefix + " is loaded"); } for (NodeData skipedNs : nsReader.getSkiped()) { log.warn("Namespace node " + skipedNs.getQPath().getName().getAsString() + " (primary type '" + skipedNs.getPrimaryTypeName().getAsString() + "') is not supported for loading. Nodes with 'exo:namespace' node type is supported only now."); } } else log.warn("Namespace storage (/jcr:system/exo:namespaces node) is not initialized. No namespaces loaded."); } /** * Copy <code>PropertyData prop</code> to new TransientItemData * * @param prop * @return * @throws RepositoryException */ private TransientItemData copyPropertyData(PropertyData prop) throws RepositoryException { if (prop == null) return null; // make a copy, value may be null for deleting items TransientPropertyData newData = new TransientPropertyData(prop.getQPath(), prop.getIdentifier(), prop.getPersistedVersion(), prop.getType(), prop.getParentIdentifier(), prop.isMultiValued(), prop.getValues()); return newData; } /** * Creates namespaces storage and fill it with given namespaces. * * @param nsSystem * @param addACL * @param namespaces * @throws RepositoryException */ private void initStorage(NodeData nsSystem, boolean addACL) throws RepositoryException { PlainChangesLog changesLog = new PlainChangesLogImpl(); TransientNodeData exoNamespaces; if (addACL) { InternalQName[] mixins = new InternalQName[]{Constants.EXO_OWNEABLE, Constants.EXO_PRIVILEGEABLE}; exoNamespaces = TransientNodeData.createNodeData(nsSystem, Constants.EXO_NAMESPACES, Constants.NT_UNSTRUCTURED, mixins); AccessControlList acl = exoNamespaces.getACL(); TransientPropertyData primaryType = TransientPropertyData.createPropertyData(exoNamespaces, Constants.JCR_PRIMARYTYPE, PropertyType.NAME, false, new TransientValueData(exoNamespaces.getPrimaryTypeName())); changesLog.add(ItemState.createAddedState(exoNamespaces)).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(exoNamespaces, Constants.JCR_MIXINTYPES, PropertyType.NAME, true, mixValues); TransientPropertyData exoOwner = TransientPropertyData.createPropertyData(exoNamespaces, 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(exoNamespaces, Constants.EXO_PERMISSIONS, ExtendedPropertyType.PERMISSION, true, permsValues); changesLog.add(ItemState.createAddedState(exoMixinTypes)).add(ItemState.createAddedState(exoOwner)).add( ItemState.createAddedState(exoPerms)); changesLog.add(new ItemState(exoNamespaces, ItemState.MIXIN_CHANGED, false, null)); } else { exoNamespaces = TransientNodeData.createNodeData(nsSystem, Constants.EXO_NAMESPACES, Constants.NT_UNSTRUCTURED); TransientPropertyData primaryType = TransientPropertyData.createPropertyData(exoNamespaces, Constants.JCR_PRIMARYTYPE, PropertyType.NAME, false, new TransientValueData(exoNamespaces.getPrimaryTypeName())); changesLog.add(ItemState.createAddedState(exoNamespaces)).add(ItemState.createAddedState(primaryType)); } nsRoot = exoNamespaces; dataManager.save(new TransactionChangesLog(changesLog)); } private boolean isInialized() { return nsRoot != null; } }