Projects >> jcr >>211eae684f87e8c6a36e1c2a91ea79ca73d872cc

Chunk
Conflicting content
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.core.nodetype.ExtendedNodeTypeManager;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
<<<<<<< HEAD
=======
import org.exoplatform.services.jcr.core.security.JCRRuntimePermissions;
import org.exoplatform.services.jcr.impl.checker.RepositoryCheckController;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
import org.exoplatform.services.jcr.impl.core.AddNamespacePluginHolder;
import org.exoplatform.services.jcr.impl.core.LocationFactory;
import org.exoplatform.services.jcr.impl.core.NamespaceDataPersister;
Solution content
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.core.nodetype.ExtendedNodeTypeManager;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
import org.exoplatform.services.jcr.core.security.JCRRuntimePermissions;
import org.exoplatform.services.jcr.impl.checker.RepositoryCheckController;
import org.exoplatform.services.jcr.impl.core.AddNamespacePluginHolder;
import org.exoplatform.services.jcr.impl.core.LocationFactory;
import org.exoplatform.services.jcr.impl.core.NamespaceDataPersister;
File
RepositoryContainer.java
Developer's decision
Version 2
Kind of conflict
Import
Chunk
Conflicting content
   private List addNamespacePlugins;

   /**
<<<<<<< HEAD
    * RepositoryContainer constructor.
    * 
    * @param parent
    *          container
    * @param config
    *          Repository configuration
    * @param addNamespacePlugins
    *          list of addNamespacePlugin
    * @throws RepositoryException
    *           container initialization error
    * @throws RepositoryConfigurationException
    *           configuration error
    */
   public RepositoryContainer(ExoContainer parent, RepositoryEntry config, List addNamespacePlugins)
      throws RepositoryException, RepositoryConfigurationException
   {

      super(new MX4JComponentAdapterFactory(), parent);

      // Defaults:
      if (config.getAccessControl() == null)
         config.setAccessControl(AccessControlPolicy.OPTIONAL);

      this.config = config;
      this.addNamespacePlugins = addNamespacePlugins;

      registerComponents();
   }

   /**
=======
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
    * RepositoryContainer constructor.
    * 
    * @param parent
Solution content
   private List addNamespacePlugins;

   /**
    * RepositoryContainer constructor.
    * 
    * @param parent
File
RepositoryContainer.java
Developer's decision
Version 2
Kind of conflict
Comment
Method declaration
Chunk
Conflicting content
               registerComponentImplementation(RepositoryIndexSearcherHolder.class);


   private void registerRepositoryComponents() throws RepositoryConfigurationException, RepositoryException
   {
<<<<<<< HEAD
      registerComponentImplementation(IdGenerator.class);
=======
      try
      {
         SecurityHelper.doPrivilegedExceptionAction(new PrivilegedExceptionAction()
         {
            public Void run() throws RepositoryConfigurationException, RepositoryException
            {

               registerComponentImplementation(RepositorySuspendController.class);
               registerComponentImplementation(RepositoryCheckController.class);
               registerComponentImplementation(IdGenerator.class);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
Solution content
   private void registerRepositoryComponents() throws RepositoryConfigurationException, RepositoryException
   {
      try
      {
         SecurityHelper.doPrivilegedExceptionAction(new PrivilegedExceptionAction()
         {
            public Void run() throws RepositoryConfigurationException, RepositoryException
            {

               registerComponentImplementation(RepositorySuspendController.class);
               registerComponentImplementation(RepositoryCheckController.class);
               registerComponentImplementation(IdGenerator.class);

               registerComponentImplementation(RepositoryIndexSearcherHolder.class);
File
RepositoryContainer.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Try statement
Chunk
Conflicting content
               registerComponentImplementation(LocationFactory.class);
               registerComponentImplementation(ValueFactoryImpl.class);

<<<<<<< HEAD
      registerComponentInstance(new AddNamespacePluginHolder(addNamespacePlugins));

      registerComponentImplementation(JCRNodeTypeDataPersister.class);
      registerComponentImplementation(NamespaceDataPersister.class);
      registerComponentImplementation(NamespaceRegistryImpl.class);
=======
               registerComponentInstance(new AddNamespacePluginHolder(addNamespacePlugins));
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

               registerComponentImplementation(JCRNodeTypeDataPersister.class);
               registerComponentImplementation(NamespaceDataPersister.class);
Solution content
               registerComponentImplementation(LocationFactory.class);
               registerComponentImplementation(ValueFactoryImpl.class);

               registerComponentInstance(new AddNamespacePluginHolder(addNamespacePlugins));

               registerComponentImplementation(JCRNodeTypeDataPersister.class);
               registerComponentImplementation(NamespaceDataPersister.class);
File
RepositoryContainer.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Chunk
Conflicting content
      }
   }

<<<<<<< HEAD
   public boolean canRemoveRepository(String name) throws RepositoryException
   {
      if (name.equals(config.getDefaultRepositoryName()))
         return false;

      RepositoryImpl repo = (RepositoryImpl)getRepository(name);
      try
      {
         RepositoryEntry repconfig = config.getRepositoryConfiguration(name);

         for (WorkspaceEntry wsEntry : repconfig.getWorkspaceEntries())
         {
            // Check non system workspaces
            if (!repo.getSystemWorkspaceName().equals(wsEntry.getName()) && !repo.canRemoveWorkspace(wsEntry.getName()))
               return false;
         }
         // check system workspace
         RepositoryContainer repositoryContainer = repositoryContainers.get(name);
         SessionRegistry sessionRegistry =
            (SessionRegistry)repositoryContainer.getComponentInstance(SessionRegistry.class);
         if (sessionRegistry == null || sessionRegistry.isInUse(repo.getSystemWorkspaceName()))
            return false;

      }
      catch (RepositoryConfigurationException e)
      {
         throw new RepositoryException(e);
      }

      return true;
   }

=======
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   /**
    * Create repository. 
* Init worksapces for initial start or them load from persistence.
Solution content
      }
   }

   /**
    * Create repository. 
* Init worksapces for initial start or them load from persistence.
File
RepositoryServiceImpl.java
Developer's decision
Version 2
Kind of conflict
Method declaration
Chunk
Conflicting content
         throw new RepositoryConfigurationException("Repository container " + rEntry.getName() + " already started");
      }

<<<<<<< HEAD
      RepositoryContainer repositoryContainer = new RepositoryContainer(parentContainer, rEntry, addNamespacesPlugins);
=======
      final RepositoryContainer repositoryContainer = new RepositoryContainer(parentContainer, rEntry, addNamespacesPlugins);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

      // Storing and starting the repository container under
      // key=repository_name
Solution content
         throw new RepositoryConfigurationException("Repository container " + rEntry.getName() + " already started");
      }

      final RepositoryContainer repositoryContainer = new RepositoryContainer(parentContainer, rEntry, addNamespacesPlugins);

      // Storing and starting the repository container under
      // key=repository_name
File
RepositoryServiceImpl.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Variable
Chunk
Conflicting content
      // key=repository_name
      try
      {
<<<<<<< HEAD
         repositoryContainers.put(rEntry.getName(), repositoryContainer);
         managerStartChanges.registerListeners(repositoryContainer);

         repositoryContainer.start();
=======
         if (repositoryContainers.putIfAbsent(rEntry.getName(), repositoryContainer) == null)
         {
            SecurityHelper.doPrivilegedAction(new PrivilegedAction()
            {
               public Void run()
               {
                  managerStartChanges.registerListeners(repositoryContainer);
                  repositoryContainer.start();
                  return null;
               }
            });
         }
         else
         {
            throw new RepositoryConfigurationException("Repository container " + rEntry.getName() + " already started");
         }
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      }
      catch (Throwable t)
      {
Solution content
      // key=repository_name
      try
      {
         if (repositoryContainers.putIfAbsent(rEntry.getName(), repositoryContainer) == null)
         {
            SecurityHelper.doPrivilegedAction(new PrivilegedAction()
            {
               public Void run()
               {
                  managerStartChanges.registerListeners(repositoryContainer);
                  repositoryContainer.start();
                  return null;
               }
            });
         }
         else
         {
            throw new RepositoryConfigurationException("Repository container " + rEntry.getName() + " already started");
         }
      }
      catch (Throwable t)
      {
File
RepositoryServiceImpl.java
Developer's decision
Version 2
Kind of conflict
If statement
Method invocation
Chunk
Conflicting content
      {
         repositoryContainers.remove(rEntry.getName());

<<<<<<< HEAD
         throw new RepositoryConfigurationException("Repository conatainer " + rEntry.getName() + " was not started.",
=======
         throw new RepositoryConfigurationException("Repository container " + rEntry.getName() + " was not started.",
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
            t);
      }
Solution content
      {
         repositoryContainers.remove(rEntry.getName());

         throw new RepositoryConfigurationException("Repository container " + rEntry.getName() + " was not started.",
            t);
      }
File
RepositoryServiceImpl.java
Developer's decision
Version 2
Kind of conflict
Throw statement
Chunk
Conflicting content
import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeManagerImpl;
import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
import org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager;
<<<<<<< HEAD
import org.exoplatform.services.jcr.impl.storage.JCRInvalidItemStateException;
import org.exoplatform.services.jcr.impl.storage.JCRItemExistsException;
import org.exoplatform.services.jcr.impl.util.io.FileCleaner;
import org.exoplatform.services.jcr.impl.util.io.SpoolFile;
import org.exoplatform.services.jcr.observation.ExtendedEvent;
=======
import org.exoplatform.services.jcr.impl.util.io.FileCleanerHolder;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

import java.io.File;
Solution content
import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeManagerImpl;
import org.exoplatform.services.jcr.impl.util.io.FileCleanerHolder;

import java.io.File;

import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
import org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager;
File
BackupWorkspaceInitializer.java
Developer's decision
Version 2
Kind of conflict
Import
Chunk
Conflicting content
      }
      else
      {
<<<<<<< HEAD
         for (int i = 0; i < this.listFixupStream.size(); i++)
         {
            List listItemState = itemDataChangesLog.getAllStates();
            ItemState itemState = listItemState.get(listFixupStream.get(i).getItemSateId());
            ItemData itemData = itemState.getData();

            TransientPropertyData propertyData = (TransientPropertyData)itemData;
            TransientValueData tvd =
               (TransientValueData)(propertyData.getValues().get(listFixupStream.get(i).getValueDataId()));

            // re-init the value
            tvd.delegate(new TransientValueData(tvd.getOrderNumber(), null, null, new SpoolFile(listFile.get(i)
               .getAbsolutePath()), fileCleaner, -1, null, true));
         }
=======
         restorePath = fullBackupPath;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      }
   }
Solution content
      }
      else
      {
         restorePath = fullBackupPath;
      }
   }
File
BackupWorkspaceInitializer.java
Developer's decision
Version 2
Kind of conflict
For statement
Variable
Chunk
Conflicting content
      PropertyImpl prevProp;
      PropertyDefinitionDatas defs;
      ItemImpl prevItem =
<<<<<<< HEAD
         dataManager.getItem(parentNode.nodeData(), new QPathEntry(propertyName, 0), true, dataManager.isNew(parentNode
            .getIdentifier()));
=======
         dataManager.getItem(parentNode.nodeData(), new QPathEntry(propertyName, 0), true,
            dataManager.isNew(parentNode.getIdentifier()), ItemType.PROPERTY, false);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

      NodeTypeDataManager ntm = session.getWorkspace().getNodeTypesHolder();
      NodeData parentData = (NodeData)parentNode.getData();
Solution content
      PropertyImpl prevProp;
      PropertyDefinitionDatas defs;
      ItemImpl prevItem =
         dataManager.getItem(parentNode.nodeData(), new QPathEntry(propertyName, 0), true,
            dataManager.isNew(parentNode.getIdentifier()), ItemType.PROPERTY, false);

      NodeTypeDataManager ntm = session.getWorkspace().getNodeTypesHolder();
      NodeData parentData = (NodeData)parentNode.getData();
File
ItemImpl.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Chunk
Conflicting content
                  registerNamespace(prefix, uri);
               }
               if (log.isDebugEnabled())
<<<<<<< HEAD
                  log.debug("Namespace is registered " + prefix + " = " + uri);
=======
               {
                  log.debug("Namespace is registered " + prefix + " = " + uri);
               }
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
            }
         }
         catch (Exception e)
Solution content
                  registerNamespace(prefix, uri);
               }
               if (log.isDebugEnabled())
               {
                  log.debug("Namespace is registered " + prefix + " = " + uri);
               }
            }
         }
         catch (Exception e)
File
NamespaceRegistryImpl.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Chunk
Conflicting content
         // 2. Try from txdatamanager
         if (!(skipCheckInPersistence))
         {
<<<<<<< HEAD
            data = transactionableManager.getItemData(parent, name);
=======
            data = transactionableManager.getItemData(parent, name, itemType, createNullItemData);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
         }
      }
      else if (!state.isDeleted())
Solution content
         // 2. Try from txdatamanager
         if (!(skipCheckInPersistence))
         {
            data = transactionableManager.getItemData(parent, name, itemType, createNullItemData);
         }
      }
      else if (!state.isDeleted())
File
SessionDataManager.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Variable
Chunk
Conflicting content
         }
         else
         {
<<<<<<< HEAD
            // TODO if (changesLog.get) check if DELETED!!

=======
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
            item = itemFactory.createItem(newData, parent);
            items.put(item.getInternalIdentifier(), new WeakReference(item));
         }
Solution content
         }
         else
         {
            item = itemFactory.createItem(newData, parent);
            items.put(item.getInternalIdentifier(), new WeakReference(item));
         }
File
SessionDataManager.java
Developer's decision
Version 2
Kind of conflict
Comment
Chunk
Conflicting content
            {
               if (item != null)
               {
<<<<<<< HEAD
                  str +=
                     (item.isNode() ? "Node\t\t" : "Property\t") + "\t" + item.isValid() + "\t" + item.isNew() + "\t"
                        + item.getInternalIdentifier() + "\t" + item.getPath() + "\n";
=======
                  str.append(item.isNode() ? "Node\t\t" : "Property\t");
                  str.append("\t").append(item.isValid());
                  str.append("\t").append(item.isNew());
                  str.append("\t").append(item.getInternalIdentifier());
                  str.append("\t").append(item.getPath()).append("\n");
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
               }
            }
         }
Solution content
            {
               if (item != null)
               {
                  str.append(item.isNode() ? "Node\t\t" : "Property\t");
                  str.append("\t").append(item.isValid());
                  str.append("\t").append(item.isNew());
                  str.append("\t").append(item.getInternalIdentifier());
                  str.append("\t").append(item.getPath()).append("\n");
               }
            }
         }
File
SessionDataManager.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Variable
Chunk
Conflicting content
import org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager;
import org.exoplatform.services.jcr.impl.util.JCRDateFormat;
import org.exoplatform.services.jcr.impl.util.io.FileCleaner;
<<<<<<< HEAD
import org.exoplatform.services.jcr.impl.util.io.SpoolFile;
=======
import org.exoplatform.services.jcr.impl.util.io.FileCleanerHolder;
import org.exoplatform.services.jcr.impl.util.io.SpoolFile;
import org.exoplatform.services.jcr.impl.xml.importing.ACLInitializationHelper;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
Solution content
import org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager;
import org.exoplatform.services.jcr.impl.util.JCRDateFormat;
import org.exoplatform.services.jcr.impl.util.io.FileCleaner;
import org.exoplatform.services.jcr.impl.util.io.FileCleanerHolder;
import org.exoplatform.services.jcr.impl.util.io.SpoolFile;
import org.exoplatform.services.jcr.impl.xml.importing.ACLInitializationHelper;
import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
File
SysViewWorkspaceInitializer.java
Developer's decision
Version 2
Kind of conflict
Import
Chunk
Conflicting content
                              {
                                 vdata =
                                    new TransientValueData(currentProperty.getValues().size(), null, null,
<<<<<<< HEAD
                                       new SpoolFile(pfile.getAbsolutePath()), fileCleaner, maxBufferSize, null, true);
=======
                                       new SpoolFile(PrivilegedFileHelper.getAbsolutePath(pfile)), fileCleaner,
                                       maxBufferSize, null, true);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
                              }
                              else
                              {
Solution content
                              {
                                 vdata =
                                    new TransientValueData(currentProperty.getValues().size(), null, null,
                                       new SpoolFile(PrivilegedFileHelper.getAbsolutePath(pfile)), fileCleaner,
                                       maxBufferSize, null, true);
                              }
                              else
                              {
File
SysViewWorkspaceInitializer.java
Developer's decision
Version 2
Kind of conflict
Attribute
Method invocation
Chunk
Conflicting content
   public QueryManager getQueryManager() throws RepositoryException
   {
      if (queryManager == null)
<<<<<<< HEAD
         throw new RepositoryException(
            "Query Manager Factory not found. Check configuration of the query-handler for workspace " + getName()
               + ".");
=======
      {
         throw new RepositoryException(
            "Query Manager Factory not found. Check configuration of the query-handler for workspace " + getName()
               + ".");
      }
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      return queryManager;
   }
Solution content
   public QueryManager getQueryManager() throws RepositoryException
   {
      if (queryManager == null)
      {
         throw new RepositoryException(
            "Query Manager Factory not found. Check configuration of the query-handler for workspace " + getName()
               + ".");
      }
      return queryManager;
   }
File
WorkspaceImpl.java
Developer's decision
Version 2
Kind of conflict
Throw statement
Chunk
Conflicting content
         this.spooled = true;
      }

<<<<<<< HEAD
      // TODO use InputStream instead of spoolFile and use Channel.transferFrom.
=======
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      public NewEditableValueData(SpoolFile spoolFile, int orderNumber, FileCleaner fileCleaner, int maxBufferSize,
         File tempDirectory) throws IOException
      {
Solution content
         this.spooled = true;
      }

      public NewEditableValueData(SpoolFile spoolFile, int orderNumber, FileCleaner fileCleaner, int maxBufferSize,
         File tempDirectory) throws IOException
      {
File
EditableValueData.java
Developer's decision
Version 2
Kind of conflict
Comment
Chunk
Conflicting content
         this.maxIOBuffSize = calcMaxIOSize();

         SpoolFile sf = SpoolFile.createTempFile("jcrvdedit", null, tempDirectory);
<<<<<<< HEAD
         OutputStream sfout = new FileOutputStream(sf);
=======
         OutputStream sfout = PrivilegedFileHelper.fileOutputStream(sf);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
         try
         {
            byte[] tmpBuff = new byte[2048];
Solution content
         {
         this.maxIOBuffSize = calcMaxIOSize();

         SpoolFile sf = SpoolFile.createTempFile("jcrvdedit", null, tempDirectory);
         OutputStream sfout = PrivilegedFileHelper.fileOutputStream(sf);
         try
            byte[] tmpBuff = new byte[2048];
File
EditableValueData.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Variable
Chunk
Conflicting content
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
<<<<<<< HEAD
import org.exoplatform.services.jcr.datamodel.NullNodeData;
=======
import org.exoplatform.services.jcr.datamodel.NullItemData;
import org.exoplatform.services.jcr.datamodel.NullNodeData;
import org.exoplatform.services.jcr.datamodel.NullPropertyData;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.datamodel.ValueData;
Solution content
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.NullItemData;
import org.exoplatform.services.jcr.datamodel.NullNodeData;
import org.exoplatform.services.jcr.datamodel.NullPropertyData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.datamodel.ValueData;
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Import
Chunk
Conflicting content
            }
         }
      }
<<<<<<< HEAD
      else if (!data.isNode())
      {
         fixPropertyValues((PropertyData)data);
      }

      return data instanceof NullNodeData ? null : data;
   }

   /**
    * {@inheritDoc}
    */
   @Override
   public ItemData getItemData(String identifier) throws RepositoryException
   {
      // 1. Try from cache
      ItemData data = getCachedItemData(identifier);

      // 2 Try from container
      if (data == null)
=======
      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_NODES);

      try
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      {
         request.start();
         if (cache.isEnabled())
Solution content
            }
         }
      }
      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_NODES);

      try
      {
         request.start();
         if (cache.isEnabled())
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Annotation
Comment
If statement
Method invocation
Method signature
Return statement
Try statement
Variable
Chunk
Conflicting content
      {
         request.done();
      }
<<<<<<< HEAD

      return data instanceof NullNodeData ? null : data;
=======
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   }

   /**
Solution content
      {
         request.done();
      }
   }

   /**
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Return statement
Variable
Chunk
Conflicting content
    * {@inheritDoc}
    */
   @Override
<<<<<<< HEAD
   public List getReferencesData(String identifier, boolean skipVersionStorage)
=======
   public List getChildNodesData(NodeData parentData, List patternFilters)
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      throws RepositoryException
   {
      return getChildNodesDataByPattern(parentData, patternFilters);
Solution content
    * {@inheritDoc}
    */
   @Override
   public List getChildNodesData(NodeData parentData, List patternFilters)
      throws RepositoryException
   {
      return getChildNodesDataByPattern(parentData, patternFilters);
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Method signature
Chunk
Conflicting content
   /**
    * {@inheritDoc}
    */
<<<<<<< HEAD
   protected List getChildNodesData(NodeData nodeData, boolean forcePersistentRead)
=======
   public ItemData getItemData(final NodeData parentData, final QPathEntry name, final ItemType itemType,
      final boolean createNullItemData)
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      throws RepositoryException
   {
      if (cache.isEnabled())
Solution content
   /**
    * {@inheritDoc}
    */
   public ItemData getItemData(final NodeData parentData, final QPathEntry name, final ItemType itemType,
      final boolean createNullItemData)
      throws RepositoryException
   {
      if (cache.isEnabled())
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Method signature
Chunk
Conflicting content
   /**
    * {@inheritDoc}
    */
<<<<<<< HEAD
   protected List getChildPropertiesData(NodeData nodeData, boolean forcePersistentRead)
      throws RepositoryException
=======
   @Override
   public List listChildPropertiesData(NodeData nodeData) throws RepositoryException
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   {
      return listChildPropertiesData(nodeData, false);
   }
Solution content
   /**
    * {@inheritDoc}
    */
   @Override
   public List listChildPropertiesData(NodeData nodeData) throws RepositoryException
   {
      return listChildPropertiesData(nodeData, false);
   }
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Annotation
Method signature
Chunk
Conflicting content
   protected ItemData getCachedItemData(NodeData parentData, QPathEntry name, ItemType itemType)
      throws RepositoryException
   {
<<<<<<< HEAD
      ItemData data = super.getItemData(parentData, name);
      if (cache.isEnabled())
      {
         cache.put(data == null ? new NullNodeData(parentData, name) : data);
      }
      return data;
=======
      return cache.isEnabled() ? cache.get(parentData.getIdentifier(), name, itemType) : null;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   }

   /**
Solution content
   protected ItemData getCachedItemData(NodeData parentData, QPathEntry name, ItemType itemType)
      throws RepositoryException
   {
      return cache.isEnabled() ? cache.get(parentData.getIdentifier(), name, itemType) : null;
   }

   /**
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Attribute
If statement
Method invocation
Return statement
Variable
Chunk
Conflicting content
    */
   protected ItemData getCachedItemData(String identifier) throws RepositoryException
   {
<<<<<<< HEAD
      ItemData data = super.getItemData(identifier);
      if (cache.isEnabled())
      {
         if (data != null)
         {
            cache.put(data);
         }
         else if (identifier != null)
         {
            cache.put(new NullNodeData(identifier));
         }
      }
      return data;
=======
      return cache.isEnabled() ? cache.get(identifier) : null;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   }

   /**
Solution content
    */
   protected ItemData getCachedItemData(String identifier) throws RepositoryException
   {
      return cache.isEnabled() ? cache.get(identifier) : null;
   }

   /**
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
If statement
Method invocation
Return statement
Variable
Chunk
Conflicting content
    * @throws RepositoryException
    *           Repository error
    */
<<<<<<< HEAD
   protected List listChildPropertiesData(NodeData nodeData, boolean forcePersistentRead)
=======
   protected List getChildNodesData(final NodeData nodeData, boolean forcePersistentRead)
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      throws RepositoryException
   {
Solution content
    * @throws RepositoryException
    *           Repository error
    */
   protected List getChildNodesData(final NodeData nodeData, boolean forcePersistentRead)
      throws RepositoryException
   {
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Method signature
Chunk
Conflicting content
    * @throws RepositoryException
    *           error
    */
<<<<<<< HEAD
   protected ValueData getPropertyValue(String propertyId, int orderNumb, int persistedVersion)
      throws IllegalStateException, RepositoryException
=======
   protected ItemData getPersistedItemData(NodeData parentData, QPathEntry name, ItemType itemType)
      throws RepositoryException
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   {
      ItemData data = super.getItemData(parentData, name, itemType);
      if (cache.isEnabled())
Solution content
    * @throws RepositoryException
    *           error
    */
   protected ItemData getPersistedItemData(NodeData parentData, QPathEntry name, ItemType itemType)
      throws RepositoryException
   {
      ItemData data = super.getItemData(parentData, name, itemType);
      if (cache.isEnabled())
File
CacheableWorkspaceDataManager.java
Developer's decision
Version 2
Kind of conflict
Method signature
Chunk
Conflicting content
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
<<<<<<< HEAD
import org.exoplatform.services.jcr.datamodel.NullNodeData;
=======
import org.exoplatform.services.jcr.datamodel.NullItemData;
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
Solution content
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.NullItemData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
File
LinkedWorkspaceStorageCacheImpl.java
Developer's decision
Version 2
Kind of conflict
Import
Chunk
Conflicting content
      if (enabled && item != null)
      {

<<<<<<< HEAD
         if (item instanceof NullNodeData)
=======
         if (item instanceof NullItemData)
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
         {
            // skip null values
            return;
Solution content
      if (enabled && item != null)
      {

         if (item instanceof NullItemData)
         {
            // skip null values
            return;
File
LinkedWorkspaceStorageCacheImpl.java
Developer's decision
Version 2
Kind of conflict
If statement
Chunk
Conflicting content
         }
      }
<<<<<<< HEAD
/*
 * 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.dataflow.persistent.jbosscache;

import org.exoplatform.container.configuration.ConfigurationManager;
import org.exoplatform.services.jcr.access.AccessControlList;
import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.exoplatform.services.jcr.config.WorkspaceEntry;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
import org.exoplatform.services.jcr.datamodel.InternalQName;
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.datamodel.NullNodeData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
   {
      try
   }
      {

         if (!inTransaction)
import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
   /**

    * {@inheritDoc}
    */
   public void put(ItemData item)
   protected final Fqn childNodes;
import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.transaction.TransactionService;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.jcr.RepositoryException;
import javax.transaction.TransactionManager;

/**
 * Created by The eXo Platform SAS.

* * Cache based on JBossCache.

* *

    *
  • cache transparent: or item cached or not, we should not generate "not found" Exceptions
  • *
  • cache consists of next resident nodes: *
      *
    • /$ITEMS - stores items by Id (i.e. /$ITEMS/itemId)
    • *
    • /$CHILD_NODES, /$CHILD_PROPS - stores items by parentId and name (i.e. /$CHILD_NODES/parentId/childName.$ITEM_ID)
    • *
    • /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST - stores child list by parentId and child Id * (i.e. /$CHILD_NODES_LIST/parentId.lists = serialized Set) * * *
    • all child properties/nodes lists should be evicted from parent at same time * i.e. for /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST we need customized eviction policy (EvictionActionPolicy) to evict * whole list on one of childs eviction *
    • * * *

      * Current state notes (subject of change): *

        *
      • cache implements WorkspaceStorageCache, without any stuff about references and locks
      • *
      • transaction style implemented via JBC barches, do with JTA (i.e. via exo's TransactionService + JBoss TM)
      • *
      • we need customized eviction policy (EvictionActionPolicy) for /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST
      • *
      * * @author Peter Nedonosko * @version $Id: JBossCacheWorkspaceStorageCache.java 13869 2008-05-05 08:40:10Z pnedonosko $ */ public class JBossCacheWorkspaceStorageCache implements WorkspaceStorageCache { private static final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.JBossCacheWorkspaceStorageCache"); public static final String JBOSSCACHE_CONFIG = "jbosscache-configuration"; public static final String ITEMS = "$ITEMS".intern(); public static final String NULL_ITEMS = "$NULL_ITEMS".intern(); public static final String CHILD_NODES = "$CHILD_NODES".intern(); public static final String CHILD_PROPS = "$CHILD_PROPS".intern(); public static final String CHILD_NODES_LIST = "$CHILD_NODES_LIST".intern(); public static final String CHILD_PROPS_LIST = "$CHILD_PROPS_LIST".intern(); public static final String LOCKS = "$LOCKS".intern(); public static final String ITEM_DATA = "$data".intern(); public static final String ITEM_ID = "$id".intern(); public static final String ITEM_LIST = "$lists".intern(); protected final BufferedJBossCache cache; protected final Fqn itemsRoot; protected final Fqn nullItemsRoot; protected final Fqn childProps; protected final Fqn childNodesList; protected final Fqn childPropsList; /** * Node order comparator for getChildNodes(). */ class NodesOrderComparator implements Comparator { /** * {@inheritDoc} */ public int compare(NodeData n1, NodeData n2) { return n1.getOrderNumber() - n2.getOrderNumber(); } } class ChildItemsIterator implements Iterator { final Iterator childs; final String parentId; final Fqn root; T next; ChildItemsIterator(Fqn root, String parentId) { this.parentId = parentId; this.root = root; Fqn parentFqn = makeChildListFqn(root, parentId); Node parent = cache.getNode(parentFqn); if (parent != null) { this.childs = cache.getChildrenNames(parentFqn).iterator(); fetchNext(); } else { this.childs = null; this.next = null; } } protected void fetchNext() { if (childs.hasNext()) { // traverse to the first existing or the end of childs T n = null; do { String itemId = (String)cache.get(makeChildFqn(root, parentId, (String)childs.next()), ITEM_ID); if (itemId != null) { n = (T)cache.get(makeItemFqn(itemId), ITEM_DATA); } } while (n == null && childs.hasNext()); next = n; } else { next = null; } } public boolean hasNext() { return next != null; } public T next() { if (next == null) { throw new NoSuchElementException(); } final T current = next; fetchNext(); return current; } public void remove() { throw new IllegalArgumentException("Not implemented"); } } class ChildNodesIterator extends ChildItemsIterator { ChildNodesIterator(String parentId) { super(childNodes, parentId); } @Override public N next() { return super.next(); } } class ChildPropertiesIterator

      extends ChildItemsIterator

      { ChildPropertiesIterator(String parentId) { super(childProps, parentId); } @Override public P next() { return super.next(); } } /** * Cache constructor with eXo TransactionService support. * * @param wsConfig WorkspaceEntry workspace config * @param transactionService TransactionService external transaction service * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(WorkspaceEntry wsConfig, TransactionService transactionService, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { if (wsConfig.getCache() == null) { throw new RepositoryConfigurationException("Cache configuration not found"); } // create cache using custom factory ExoJBossCacheFactory factory; if (transactionService != null) { factory = new ExoJBossCacheFactory(cfm, transactionService.getTransactionManager()); } else { factory = new ExoJBossCacheFactory(cfm); } this.cache = new BufferedJBossCache(factory.createCache(wsConfig.getCache())); this.itemsRoot = Fqn.fromElements(ITEMS); this.nullItemsRoot = Fqn.fromElements(NULL_ITEMS); this.childNodes = Fqn.fromElements(CHILD_NODES); this.childProps = Fqn.fromElements(CHILD_PROPS); this.childNodesList = Fqn.fromElements(CHILD_NODES_LIST); this.childPropsList = Fqn.fromElements(CHILD_PROPS_LIST); this.cache.create(); this.cache.start(); createResidentNode(childNodes); createResidentNode(childNodesList); createResidentNode(childProps); createResidentNode(childPropsList); createResidentNode(itemsRoot); createResidentNode(nullItemsRoot); } /** * Cache constructor with JBossCache JTA transaction support. * * @param wsConfig WorkspaceEntry workspace config * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(WorkspaceEntry wsConfig, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { this(wsConfig, null, cfm); } /** * Checks if node with give FQN not exists and creates resident node. * @param fqn */ protected void createResidentNode(Fqn fqn) { Node cacheRoot = cache.getRoot(); if (!cacheRoot.hasChild(fqn)) { cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true); cacheRoot.addChild(fqn).setResident(true); } else { cache.getNode(fqn).setResident(true); } } protected static String readJBCConfig(final WorkspaceEntry wsConfig) throws RepositoryConfigurationException { if (wsConfig.getCache() != null) { return wsConfig.getCache().getParameterValue(JBOSSCACHE_CONFIG); } else { throw new RepositoryConfigurationException("Cache configuration not found"); } } /** * Return TransactionManager used by JBossCache backing the JCR cache. * * @return TransactionManager */ public TransactionManager getTransactionManager() { return cache.getTransactionManager(); } boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (item instanceof NullNodeData) { putNullNode((NullNodeData)item); } else { if (item.isNode()) { putNode((NodeData)item, ModifyChildOption.NOT_MODIFY); } else { putProperty((PropertyData)item, ModifyChildOption.NOT_MODIFY); } } } finally { cache.setLocal(false); if (!inTransaction) { cache.commitTransaction(); } } } /** * {@inheritDoc} */ public void remove(ItemData item) { removeItem(item); } /** * {@inheritDoc} */ public void onSaveItems(final ItemStateChangesLog itemStates) { // if something happen we will rollback changes boolean rollback = true; try { cache.beginTransaction(); for (ItemState state : itemStates.getAllStates()) { if (state.isAdded()) { if (state.isPersisted()) { putItem(state.getData()); } } else if (state.isUpdated()) { if (state.isPersisted()) { // There was a problem with removing a list of samename siblings in on transaction, // so putItemInBufferedCache(..) and updateInBufferedCache(..) used instead put(..) and update (..) methods. ItemData prevItem = putItemInBufferedCache(state.getData()); if (prevItem != null && state.isNode()) { // nodes reordered, if previous is null it's InvalidItemState case updateInBuffer((NodeData)state.getData(), (NodeData)prevItem); } } } else if (state.isDeleted()) { removeItem(state.getData()); } else if (state.isRenamed()) { putItem(state.getData()); } else if (state.isMixinChanged()) { if (state.isPersisted()) { // update subtree ACLs updateMixin((NodeData)state.getData()); } } } cache.commitTransaction(); rollback = false; } finally { if (rollback) { cache.rollbackTransaction(); /** * {@inheritDoc} */ public void addChildNodes(NodeData parent, List childs) { boolean inTransaction = cache.isTransactionActive(); { cache.beginTransaction(); } cache.setLocal(true); // remove previous all (to be sure about consistency) cache.removeNode(makeChildListFqn(childNodesList, parent.getIdentifier())); if (childs.size() > 0) { Set set = new HashSet(); for (NodeData child : childs) { putNode(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.put(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, set); } else { // cache fact of empty childs list cache.put(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, Collections.EMPTY_SET); } } finally { cache.setLocal(false); if (!inTransaction) { cache.commitTransaction(); } } } /** * {@inheritDoc} */ public void addChildProperties(NodeData parent, List childs) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); // remove previous all (to be sure about consistency) cache.removeNode(makeChildListFqn(childPropsList, parent.getIdentifier())); if (childs.size() > 0) { // add all new Set set = new HashSet(); for (PropertyData child : childs) { putProperty(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.put(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, set); } else { cache.put(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, Collections.EMPTY_SET); } } finally { cache.setLocal(false); if (!inTransaction) { cache.commitTransaction(); } } } /** * {@inheritDoc} */ public void addChildPropertiesList(NodeData parent, List childProperties) { // TODO not implemented, will force read from DB // try // { // cache.beginTransaction(); // cache.setLocal(true); // // } // finally // { // cache.setLocal(false); // cache.commitTransaction(); // } } /** * {@inheritDoc} */ public ItemData get(String parentId, QPathEntry name) { // get as node first String itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID); if (itemId != null) { return getFromCacheById(itemId); } // try as property QPath itemId = (String)cache.get(makeChildFqn(childProps, parentId, name), ITEM_ID); if (itemId != null) { return getFromCacheById(itemId); } return (ItemData)cache.get(makeNullItemFqn(parentId + "$" + name.getAsString(true)), ITEM_DATA); } /** * {@inheritDoc} */ public ItemData get(String id) { ItemData data = getFromCacheById(id); return data != null ? data : (ItemData)cache.get(makeNullItemFqn(id), ITEM_DATA); } /** * {@inheritDoc} */ public List getChildNodes(final NodeData parent) { final List childs = new ArrayList(); // get list of children uuids final Set set = (Set)cache.get(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST); if (set != null) { for (Object child : set) { NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (node == null) { return null; } childs.add(node); } // order children by orderNumber, as HashSet returns children in other order Collections.sort(childs, new NodesOrderComparator()); return childs; } else { return null; } } /** * {@inheritDoc} */ public List getChildProperties(NodeData parent) { return getChildProps(parent.getIdentifier(), true); } /** * {@inheritDoc} */ public List listChildProperties(NodeData parent) { return getChildProps(parent.getIdentifier(), false); } /** * Internal get child properties. * * @param parentId String * @param withValue boolean, if true only "full" Propeties can be returned * @return List of PropertyData */ protected List getChildProps(String parentId, boolean withValue) { final List childs = new ArrayList(); // get set of property uuids final Set set = (Set)cache.get(makeChildListFqn(childPropsList, parentId), ITEM_LIST); if (set != null) { for (Object child : set) { PropertyData prop = (PropertyData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (prop == null) { return null; } if (withValue && prop.getValues().size() <= 0) { // don't return list of empty-valued props (but listChildProperties() can) return null; } childs.add(prop); } return childs; } else { return null; } } /** * {@inheritDoc} */ public long getSize() { // Total number of JBC nodes in the cache - the total amount of resident nodes return cache.getNumberOfNodes() - 5; } /** * {@inheritDoc} */ public boolean isEnabled() { return true; } // non-public members /** * Make Item absolute Fqn, i.e. /$ITEMS/itemID. * * @param itemId String * @return Fqn */ protected Fqn makeItemFqn(String itemId) { return Fqn.fromRelativeElements(itemsRoot, itemId); } /** * Make Item absolute Fqn, i.e. /$NULL_ITEMS/itemID. * * @param itemId String * @return Fqn */ protected Fqn makeNullItemFqn(String itemId) { return Fqn.fromRelativeElements(nullItemsRoot, itemId); } /** * Make child Item absolute Fqn, i.e. /root/parentId/childName. * * @param root Fqn * @param parentId String * @param childName QPathEntry * @return Fqn */ protected Fqn makeChildFqn(Fqn root, String parentId, QPathEntry childName) { return Fqn.fromRelativeElements(root, parentId, childName.getAsString(true)); } /** * Make child Item absolute Fqn, i.e. /root/parentId/childName. * * @param root Fqn * @param parentId String * @param childName String * @return Fqn */ protected Fqn makeChildFqn(Fqn root, String parentId, String childName) { return Fqn.fromRelativeElements(root, parentId, childName); } /** * Make child node parent absolute Fqn, i.e. /root/itemId. * * @param root Fqn * @param parentId String * @return Fqn */ protected Fqn makeChildListFqn(Fqn root, String parentId) { return Fqn.fromRelativeElements(root, parentId); } /** * Gets item data from cache by item identifier. */ protected ItemData getFromCacheById(String id) { return (ItemData)cache.get(makeItemFqn(id), ITEM_DATA); } /** * Internal put Item. * * @param item ItemData, new data to put in the cache * @return ItemData, previous data or null */ protected ItemData putItem(ItemData item) { if (item.isNode()) { return putNode((NodeData)item, ModifyChildOption.MODIFY); } else { return putProperty((PropertyData)item, ModifyChildOption.MODIFY); } } protected ItemData putItemInBufferedCache(ItemData item) { if (item.isNode()) { return putNodeInBufferedCache((NodeData)item, ModifyChildOption.MODIFY); } else { return putProperty((PropertyData)item, ModifyChildOption.MODIFY); } } /** * Internal put Node. * } * @param node, NodeData, new data to put in the cache * @return NodeData, previous data or null */ protected ItemData putNode(NodeData node, ModifyChildOption modifyListsOfChild) { removeNullNode(node); // if not a root node if (node.getParentIdentifier() != null) { // add in CHILD_NODES cache.put(makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath() .getEntries().length - 1]), ITEM_ID, node.getIdentifier()); // if MODIFY and List present OR FORCE_MODIFY, then write if ((modifyListsOfChild == ModifyChildOption.MODIFY && cache.getNode(makeChildListFqn(childNodesList, node .getParentIdentifier())) != null) || modifyListsOfChild == ModifyChildOption.FORCE_MODIFY) { cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node .getIdentifier()); } } // add in ITEMS return (ItemData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node); } /** * Internal put NullNode. * * @param node, NodeData, new data to put in the cache * @return ItemData, previous data or null */ protected ItemData putNullNode(NullNodeData node) { return (ItemData)cache.put(makeNullItemFqn(node.getIdentifier()), ITEM_DATA, node); } /** * Removes NullNode from cache. * * @param item * that possible has corresponding NullNode in cache * */ protected void removeNullNode(ItemData item) { // remove possible NullNodeData from cache boolean local = cache.isLocal(); cache.setLocal(true); Fqn fqn = makeNullItemFqn(item.getIdentifier()); if ((NullNodeData)cache.get(fqn, ITEM_DATA) != null) { cache.removeNode(fqn); } fqn = makeNullItemFqn(item.getParentIdentifier() + "$" + item.getQPath().getEntries()[item.getQPath().getEntries().length - 1].getAsString(true)); if (cache.get(fqn, ITEM_DATA) != null) { cache.removeNode(fqn); } cache.setLocal(local); } protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption modifyListsOfChild) { // if not a root node if (node.getParentIdentifier() != null) { // add in CHILD_NODES cache.put(makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath() .getEntries().length - 1]), ITEM_ID, node.getIdentifier()); // if MODIFY and List present OR FORCE_MODIFY, then write if ((modifyListsOfChild == ModifyChildOption.MODIFY && cache.getNode(makeChildListFqn(childNodesList, node .getParentIdentifier())) != null) || modifyListsOfChild == ModifyChildOption.FORCE_MODIFY) { cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node .getIdentifier()); } } // add in ITEMS return (ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node); } /** * Internal put Property. * * @param node, PropertyData, new data to put in the cache * @return PropertyData, previous data or null */ protected PropertyData putProperty(PropertyData prop, ModifyChildOption modifyListsOfChild) { removeNullNode(prop); // add in CHILD_PROPS cache.put(makeChildFqn(childProps, prop.getParentIdentifier(), prop.getQPath().getEntries()[prop.getQPath() .getEntries().length - 1]), ITEM_ID, prop.getIdentifier()); // if MODIFY and List present OR FORCE_MODIFY, then write if ((modifyListsOfChild == ModifyChildOption.MODIFY && cache.getNode(makeChildListFqn(childPropsList, prop .getParentIdentifier())) != null) || modifyListsOfChild == ModifyChildOption.FORCE_MODIFY) { cache.addToList(makeChildListFqn(childPropsList, prop.getParentIdentifier()), ITEM_LIST, prop.getIdentifier()); } ItemData result = get(prop.getParentIdentifier(), prop.getQPath().getEntries()[prop.getQPath().getEntries().length - 1]); // add in ITEMS return (PropertyData)cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop); } protected void removeItem(ItemData item) { if (item.isNode()) { if (item.getParentIdentifier() != null) { // if not a root node // remove from CHILD_NODES of parent cache.removeNode(makeChildFqn(childNodes, item.getParentIdentifier(), item.getQPath().getEntries()[item .getQPath().getEntries().length - 1])); // remove from CHILD_NODES_LIST of parent cache.removeFromList(makeChildListFqn(childNodesList, item.getParentIdentifier()), ITEM_LIST, item .getIdentifier()); // remove from CHILD_NODES as parent cache.removeNode(makeChildListFqn(childNodes, item.getIdentifier())); // remove from CHILD_NODES_LIST as parent cache.removeNode(makeChildListFqn(childNodesList, item.getIdentifier())); // remove from CHILD_PROPS as parent cache.removeNode(makeChildListFqn(childProps, item.getIdentifier())); // remove from CHILD_PROPS_LIST as parent cache.removeNode(makeChildListFqn(childPropsList, item.getIdentifier())); } } else { // remove from CHILD_PROPS cache.removeNode(makeChildFqn(childProps, item.getParentIdentifier(), item.getQPath().getEntries()[item .getQPath().getEntries().length - 1])); // remove from CHILD_PROPS_LIST cache.removeFromList(makeChildListFqn(childPropsList, item.getParentIdentifier()), ITEM_LIST, item .getIdentifier()); } // remove from ITEMS cache.removeNode(makeItemFqn(item.getIdentifier())); } /** * Update Node's mixin and ACL. * * @param node NodeData */ protected void updateMixin(NodeData node) { NodeData prevData = (NodeData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node); if (prevData != null) { // do update ACL if needed if (prevData.getACL() == null || !prevData.getACL().equals(node.getACL())) { updateChildsACL(node.getIdentifier(), node.getACL()); } } else if (LOG.isDebugEnabled()) { LOG.debug("Previous NodeData not found for mixin update " + node.getQPath().getAsString()); } } /** * Update Node hierachy in case of same-name siblings reorder. * Assumes the new (updated) nodes already putted in the cache. Previous name of updated nodes will be calculated * and that node will be deleted (if has same id as the new node). Childs paths will be updated to a new node path. * * @param node NodeData * @param prevNode NodeData */ protected void update(final NodeData node, final NodeData prevNode) { // get previously cached NodeData and using its name remove child on the parent Fqn prevFqn = makeChildFqn(childNodes, node.getParentIdentifier(), prevNode.getQPath().getEntries()[prevNode.getQPath() .getEntries().length - 1]); if (node.getIdentifier().equals(cache.get(prevFqn, ITEM_ID))) { // it's same-name siblings re-ordering, delete previous child if (!cache.removeNode(prevFqn) && LOG.isDebugEnabled()) { LOG.debug("Node not extists as a child but update asked " + node.getQPath().getAsString()); } } // update childs paths if index changed int nodeIndex = node.getQPath().getEntries()[node.getQPath().getEntries().length - 1].getIndex(); int prevNodeIndex = prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1].getIndex(); if (nodeIndex != prevNodeIndex) { updateTreePath(node.getIdentifier(), node.getQPath(), null); // don't change ACL, it's same parent } } /** * This method duplicate update method, except using getFromBuffer inside. * * @param node NodeData * @param prevNode NodeData */ protected void updateInBuffer(final NodeData node, final NodeData prevNode) { // get previously cached NodeData and using its name remove child on the parent Fqn prevFqn = makeChildFqn(childNodes, node.getParentIdentifier(), prevNode.getQPath().getEntries()[prevNode.getQPath() .getEntries().length - 1]); if (node.getIdentifier().equals(cache.getFromBuffer(prevFqn, ITEM_ID))) { // it's same-name siblings re-ordering, delete previous child if (!cache.removeNode(prevFqn) && LOG.isDebugEnabled()) { LOG.debug("Node not extists as a child but update asked " + node.getQPath().getAsString()); } } // update childs paths if index changed int nodeIndex = node.getQPath().getEntries()[node.getQPath().getEntries().length - 1].getIndex(); int prevNodeIndex = prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1].getIndex(); if (nodeIndex != prevNodeIndex) { updateTreePath(node.getIdentifier(), node.getQPath(), null); // don't change ACL, it's same parent } } /** * Update Nodes tree with new path. * * @param parentId String - root node id of JCR subtree. * @param rootPath QPath * @param acl AccessControlList */ protected void updateTreePath(final String parentId, final QPath rootPath, final AccessControlList acl) { boolean inheritACL = acl != null; // update properties for (Iterator iter = new ChildPropertiesIterator(parentId); iter.hasNext();) { PropertyData prevProp = iter.next(); if (inheritACL && (prevProp.getQPath().getName().equals(Constants.EXO_PERMISSIONS) || prevProp.getQPath().getName() .equals(Constants.EXO_OWNER))) { inheritACL = false; } // recreate with new path for child Props only QPath newPath = QPath .makeChildPath(rootPath, prevProp.getQPath().getEntries()[prevProp.getQPath().getEntries().length - 1]); TransientPropertyData newProp = new TransientPropertyData(newPath, prevProp.getIdentifier(), prevProp.getPersistedVersion(), prevProp .getType(), prevProp.getParentIdentifier(), prevProp.isMultiValued(), prevProp.getValues()); cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp); } // update child nodes for (Iterator iter = new ChildNodesIterator(parentId); iter.hasNext();) { NodeData prevNode = iter.next(); // recreate with new path for child Nodes only QPath newPath = .makeChildPath(rootPath, prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1]); TransientNodeData newNode = new TransientNodeData(newPath, prevNode.getIdentifier(), prevNode.getPersistedVersion(), prevNode .getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode .getParentIdentifier(), inheritACL ? acl : prevNode.getACL()); // TODO check ACL // update this node cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode); // update childs recursive updateTreePath(newNode.getIdentifier(), newNode.getQPath(), inheritACL ? acl : null); } } /** * Update child Nodes ACLs. * * @param parentId String - root node id of JCR subtree. * @param acl AccessControlList */ protected void updateChildsACL(final String parentId, final AccessControlList acl) { for (Iterator iter = new ChildNodesIterator(parentId); iter.hasNext();) { NodeData prevNode = iter.next(); // is ACL changes on this node (i.e. ACL inheritance brokes) for (InternalQName mixin : prevNode.getMixinTypeNames()) { if (mixin.equals(Constants.EXO_PRIVILEGEABLE) || mixin.equals(Constants.EXO_OWNEABLE)) { continue; } } // recreate with new path for child Nodes only TransientNodeData newNode = new TransientNodeData(prevNode.getQPath(), prevNode.getIdentifier(), prevNode.getPersistedVersion(), prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode .getParentIdentifier(), acl); // update this node cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode); // update childs recursive updateChildsACL(newNode.getIdentifier(), acl); } } public void beginTransaction() { cache.beginTransaction(); } public void commitTransaction() { cache.commitTransaction(); } public void rollbackTransaction() { cache.rollbackTransaction(); } /** * {@inheritDoc} */ public boolean isTXAware() { return true; } /** *
    • NOT_MODIFY - node(property) is not added to the parent's list (no persistent changes performed, cache used as cache)
    • *
    • MODIFY - node(property) is added to the parent's list if parent in the cache (new item is added to persistent, add to list if it is present)
    • *
    • FORCE_MODIFY - node(property) is added to the parent's list anyway (when list is read from DB, forcing write)
    • */ private enum ModifyChildOption { NOT_MODIFY, MODIFY, FORCE_MODIFY } } ======= /* * 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.dataflow.persistent.jbosscache; import org.exoplatform.commons.utils.SecurityHelper; import org.exoplatform.container.ExoContainerContext; import org.exoplatform.container.configuration.ConfigurationManager; import org.exoplatform.management.annotations.Managed; import org.exoplatform.management.annotations.ManagedDescription; import org.exoplatform.services.jcr.access.AccessControlList; import org.exoplatform.services.jcr.config.RepositoryConfigurationException; import org.exoplatform.services.jcr.config.WorkspaceEntry; import org.exoplatform.services.jcr.dataflow.ItemState; import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog; import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData; import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData; import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache; import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener; import org.exoplatform.services.jcr.datamodel.IllegalPathException; 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.NullItemData; import org.exoplatform.services.jcr.datamodel.NullNodeData; import org.exoplatform.services.jcr.datamodel.NullPropertyData; import org.exoplatform.services.jcr.datamodel.PropertyData; import org.exoplatform.services.jcr.datamodel.QPath; 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.backup.BackupException; import org.exoplatform.services.jcr.impl.backup.Backupable; import org.exoplatform.services.jcr.impl.backup.DataRestore; import org.exoplatform.services.jcr.impl.backup.rdbms.DataRestoreContext; import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter; import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData; import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory; import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory.CacheType; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.transaction.ActionNonTxAware; import org.exoplatform.services.transaction.TransactionService; import org.jboss.cache.Cache; import org.jboss.cache.CacheStatus; import org.jboss.cache.Fqn; import org.jboss.cache.Node; import org.jboss.cache.config.Configuration.CacheMode; import org.jboss.cache.config.EvictionRegionConfig; import org.jboss.cache.eviction.ExpirationAlgorithmConfig; import org.jboss.cache.jmx.JmxRegistrationManager; import org.picocontainer.Startable; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.transaction.TransactionManager; /** * Created by The eXo Platform SAS.

      * * Cache based on JBossCache.

      * *

        *
      • cache transparent: or item cached or not, we should not generate "not found" Exceptions
      • *
      • cache consists of next resident nodes: *
          *
        • /$ITEMS - stores items by Id (i.e. /$ITEMS/itemId)
        • protected final Fqn rootFqn; *
        • /$CHILD_NODES, /$CHILD_PROPS - stores items by parentId and name (i.e. /$CHILD_NODES/parentId/childName.$ITEM_ID)
        • *
        • /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST - stores child list by parentId and child Id * (i.e. /$CHILD_NODES_LIST/parentId.lists = serialized Set) * * } *
        • all child properties/nodes lists should be evicted from parent at same time * i.e. for /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST we need customized eviction policy (EvictionActionPolicy) to evict * whole list on one of childs eviction *
        • * * *

          * Current state notes (subject of change): *

            *
          • cache implements WorkspaceStorageCache, without any stuff about references and locks
          • *
          • transaction style implemented via JBC barches, do with JTA (i.e. via exo's TransactionService + JBoss TM)
          • *
          • we need customized eviction policy (EvictionActionPolicy) for /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST
          • *
          * * @author Peter Nedonosko * @version $Id: JBossCacheWorkspaceStorageCache.java 13869 2008-05-05 08:40:10Z pnedonosko $ */ public class JBossCacheWorkspaceStorageCache implements WorkspaceStorageCache, Startable, Backupable { private static final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.JBossCacheWorkspaceStorageCache"); private final boolean enabled; private final boolean shareable; public static final String JBOSSCACHE_CONFIG = "jbosscache-configuration"; public static final String JBOSSCACHE_EXPIRATION = "jbosscache-expiration-time"; /** * Indicate whether the JBoss Cache instance used can be shared with other caches */ public static final String JBOSSCACHE_SHAREABLE = "jbosscache-shareable"; public static final Boolean JBOSSCACHE_SHAREABLE_DEFAULT = Boolean.FALSE; public static final long JBOSSCACHE_EXPIRATION_DEFAULT = 900000; // 15 minutes public static final String ITEMS = "$ITEMS".intern(); public static final String NULL_ITEMS = "$NULL_ITEMS".intern(); public static final String CHILD_NODES = "$CHILD_NODES".intern(); public static final String CHILD_PROPS = "$CHILD_PROPS".intern(); public static final String CHILD_NODES_LIST = "$CHILD_NODES_LIST".intern(); public static final String CHILD_PROPS_LIST = "$CHILD_PROPS_LIST".intern(); public static final String CHILD_PROPS_BY_PATTERN_LIST = "$CHILD_PROPS_BY_PATTERN_LIST".intern(); public static final String CHILD_NODES_BY_PATTERN_LIST = "$CHILD_NODES_BY_PATTERN_LIST".intern(); public static final String CHILD_NODES_BY_PAGE_LIST = "$CHILD_NODES_BY_PAGE_LIST".intern(); public static final String LOCKS = "$LOCKS".intern(); public static final String REFERENCE = "$REFERENCE".intern(); public static final String ITEM_DATA = "$data".intern(); public static final String ITEM_ID = "$id".intern(); public static final String ITEM_LIST = "$lists".intern(); public static final String PATTERN_OBJ = "$pattern".intern(); protected final BufferedJBossCache cache; protected final Fqn itemsRoot; protected final Fqn refRoot; protected final Fqn childNodes; protected final Fqn childProps; protected final Fqn childNodesList; protected final Fqn childPropsList; protected final Fqn childNodesByPageList; protected final Fqn childPropsByPatternList; protected final Fqn childNodesByPatternList; private final CacheActionNonTxAware commitTransaction = new CacheActionNonTxAware() { @Override protected Void execute(Void arg) throws RuntimeException { cache.commitTransaction(); return null; } }; private final CacheActionNonTxAware getFromCacheById = new CacheActionNonTxAware() { @Override protected ItemData execute(String id) throws RuntimeException { return getFromCacheById(id); } }; private final CacheActionNonTxAware, NodeData> getChildNodes = new CacheActionNonTxAware, NodeData>() { @Override protected List execute(NodeData parent) throws RuntimeException { // empty Set marks that there is no child nodes // get list of children uuids final Set set = (Set)cache.get(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (node == null) { return null; } childs.add(node); } // order children by orderNumber, as HashSet returns children in other order Collections.sort(childs, new NodesOrderComparator()); return childs; } else { return null; } } }; private final CacheActionNonTxAware getFromCacheByPath = new CacheActionNonTxAware() { @Override protected ItemData execute(Object... args) throws RuntimeException { String parentId = (String)args[0]; QPathEntry name = (QPathEntry)args[1]; ItemType itemType = (ItemType)args[2]; String itemId = null; if (itemType == ItemType.UNKNOWN) { // Try as node first. itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID); if (itemId == null || itemId.equals(NullItemData.NULL_ID)) { // node with such a name is not found or marked as not-exist, so check the properties String propId = (String)cache.get(makeChildFqn(childProps, parentId, name), ITEM_ID); if (propId != null) { itemId = propId; } } } else if (itemType == ItemType.NODE) { itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID); } else { itemId = (String)cache.get(makeChildFqn(childProps, parentId, name), ITEM_ID); } if (itemId != null) { if (itemId.equals(NullItemData.NULL_ID)) { if (itemType == ItemType.UNKNOWN || itemType == ItemType.NODE) { return new NullNodeData(); } else { return new NullPropertyData(); else { return get(itemId); } } return null; } }; private final CacheActionNonTxAware getChildNodesCount = new CacheActionNonTxAware() { @Override protected Integer execute(NodeData parent) throws RuntimeException { // get list of children uuids final Set set = (Set)cache.get(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST); return set != null ? set.size() : -1; } }; private final CacheActionNonTxAware, Object> getChildProps = new CacheActionNonTxAware, Object>() { @Override protected List execute(Object... args) throws RuntimeException { String parentId = (String)args[0]; boolean withValue = (Boolean)args[1]; // get set of property uuids final Set set = (Set)cache.get(makeChildListFqn(childPropsList, parentId), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { PropertyData prop = (PropertyData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (prop == null || prop instanceof NullItemData) { return null; } if (withValue && prop.getValues().size() <= 0) { // don't return list of empty-valued props (but listChildProperties() can) return null; } childs.add(prop); } return childs; } else { return null; } } }; private final CacheActionNonTxAware, String> getReferencedProperties = new CacheActionNonTxAware, String>() { @Override protected List execute(String identifier) throws RuntimeException { // get set of property uuids final Set set = (Set)cache.get(makeRefFqn(identifier), ITEM_LIST); if (set != null) { final List props = new ArrayList(); for (String propId : set) { PropertyData prop = (PropertyData)cache.get(makeItemFqn(propId), ITEM_DATA); if (prop == null || prop instanceof NullItemData) { return null; } // add property as many times as has referenced values List lData = prop.getValues(); for (int i = 0, length = lData.size(); i < length; i++) { ValueData vdata = lData.get(i); try { if (new String(vdata.getAsByteArray(), Constants.DEFAULT_ENCODING).equals(identifier)) { public T next() props.add(prop); } } catch (IllegalStateException e) { // Do not nothing. } catch (IOException e) { // Do not nothing. } } } return props; } else { return null; } } }; private final CacheActionNonTxAware getSize = new CacheActionNonTxAware() { @Override protected Long execute(Void arg) throws RuntimeException { // Total number of JBC nodes in the cache - the total amount of resident nodes return numNodes(cache.getNode(rootFqn)) - 10; } }; /** * Indicates whether the cache has already been initialized or not */ protected volatile boolean initialized; private JmxRegistrationManager jmxManager; /** * Node order comparator for getChildNodes(). */ class NodesOrderComparator implements Comparator { /** * {@inheritDoc} */ public int compare(NodeData n1, NodeData n2) { return n1.getOrderNumber() - n2.getOrderNumber(); } } class ChildItemsIterator implements Iterator { final Iterator childs; final String parentId; final Fqn root; T next; ChildItemsIterator(Fqn root, String parentId) { this.parentId = parentId; this.root = root; Fqn parentFqn = makeChildListFqn(root, parentId); Node parent = cache.getNode(parentFqn); if (parent != null) { this.childs = cache.getChildrenNames(parentFqn).iterator(); fetchNext(); } else { this.childs = null; this.next = null; } } protected void fetchNext() { if (childs.hasNext()) { // traverse to the first existing or the end of childs T n = null; do { String itemId = (String)cache.get(makeChildFqn(root, parentId, (String)childs.next()), ITEM_ID); if (itemId != null) { n = (T)cache.get(makeItemFqn(itemId), ITEM_DATA); } } while (n == null && childs.hasNext()); next = n; } else { next = null; } } public boolean hasNext() { return next != null; } { if (next == null) { throw new NoSuchElementException(); } }); final T current = next; fetchNext(); return current; } public void remove() { throw new IllegalArgumentException("Not implemented"); } } class ChildNodesIterator extends ChildItemsIterator { ChildNodesIterator(String parentId) { super(childNodes, parentId); } @Override public N next() { return super.next(); } } class ChildPropertiesIterator

          extends ChildItemsIterator

          { ChildPropertiesIterator(String parentId) { super(childProps, parentId); } @Override public P next() { return super.next(); } } /** * Cache constructor with eXo TransactionService support. * * @param ctx The container context * @param wsConfig WorkspaceEntry workspace config * @param transactionService TransactionService external transaction service * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(ExoContainerContext ctx, WorkspaceEntry wsConfig, TransactionService transactionService, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { if (wsConfig.getCache() == null) { throw new RepositoryConfigurationException("Cache configuration not found"); } enabled = wsConfig.getCache().isEnabled(); shareable = wsConfig.getCache().getParameterBoolean(JBOSSCACHE_SHAREABLE, JBOSSCACHE_SHAREABLE_DEFAULT).booleanValue(); // create cache using custom factory ExoJBossCacheFactory factory; if (transactionService != null) { factory = new ExoJBossCacheFactory(cfm, transactionService.getTransactionManager()); } else { factory = new ExoJBossCacheFactory(cfm); } // create parent JBossCache instance Cache parentCache = factory.createCache(wsConfig.getCache()); // get all eviction configurations List evictionConfigurations = parentCache.getConfiguration().getEvictionConfig().getEvictionRegionConfigs(); // append and default eviction configuration, since it is not present in region configurations evictionConfigurations.add(parentCache.getConfiguration().getEvictionConfig().getDefaultEvictionRegionConfig()); boolean useExpiration = false; // looking over all eviction configurations till the end or till some expiration algorithm subclass not found. for (EvictionRegionConfig evictionRegionConfig : evictionConfigurations) { if (evictionRegionConfig.getEvictionAlgorithmConfig() instanceof ExpirationAlgorithmConfig) { // force set expiration key to default value in all Expiration configurations (if any) ((ExpirationAlgorithmConfig)evictionRegionConfig.getEvictionAlgorithmConfig()) .setExpirationKeyName(ExpirationAlgorithmConfig.EXPIRATION_KEY); useExpiration = true; } } if (useExpiration) { LOG.info("Using BufferedJBossCache compatible with Expiration algorithm."); } this.rootFqn = Fqn.fromElements(wsConfig.getUniqueName()); parentCache = ExoJBossCacheFactory.getUniqueInstance(CacheType.JCR_CACHE, rootFqn, parentCache, wsConfig.getCache() .getParameterBoolean(JBOSSCACHE_SHAREABLE, JBOSSCACHE_SHAREABLE_DEFAULT).booleanValue()); if (ctx != null) { this.jmxManager = ExoJBossCacheFactory.getJmxRegistrationManager(ctx, parentCache, CacheType.JCR_CACHE); } // if expiration is used, set appropriate factory with with timeout set via configuration (or default one 15minutes) this.cache = new BufferedJBossCache(parentCache, useExpiration, wsConfig.getCache().getParameterTime(JBOSSCACHE_EXPIRATION, JBOSSCACHE_EXPIRATION_DEFAULT)); this.itemsRoot = Fqn.fromRelativeElements(rootFqn, ITEMS); this.refRoot = Fqn.fromRelativeElements(rootFqn, REFERENCE); this.childNodes = Fqn.fromRelativeElements(rootFqn, CHILD_NODES); this.childProps = Fqn.fromRelativeElements(rootFqn, CHILD_PROPS); this.childNodesList = Fqn.fromRelativeElements(rootFqn, CHILD_NODES_LIST); this.childPropsList = Fqn.fromRelativeElements(rootFqn, CHILD_PROPS_LIST); this.childNodesByPageList = Fqn.fromRelativeElements(rootFqn, CHILD_NODES_BY_PAGE_LIST); this.childPropsByPatternList = Fqn.fromRelativeElements(rootFqn, CHILD_PROPS_BY_PATTERN_LIST); this.childNodesByPatternList = Fqn.fromRelativeElements(rootFqn, CHILD_NODES_BY_PATTERN_LIST); if (cache.getConfiguration().getCacheMode() == CacheMode.LOCAL) { // The cache is local so we have no risk to get replication exception // during the initialization phase init(); } } /** * Cache constructor with eXo TransactionService support. * * @param wsConfig WorkspaceEntry workspace config * @param transactionService TransactionService external transaction service * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(WorkspaceEntry wsConfig, TransactionService transactionService, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { this(null, wsConfig, transactionService, cfm); } /** * Cache constructor with JBossCache JTA transaction support. * * @param ctx The container context * @param wsConfig WorkspaceEntry workspace config * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(ExoContainerContext ctx, WorkspaceEntry wsConfig, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { this(ctx, wsConfig, null, cfm); } /** * Creates, starts and initialize the cache */ private void init() { if (initialized) { // The cache has already been initialized return; } this.cache.create(); this.cache.start(); createResidentNode(childNodes); createResidentNode(refRoot); createResidentNode(childNodesList); createResidentNode(childProps); createResidentNode(childPropsList); createResidentNode(childNodesByPageList); createResidentNode(childPropsByPatternList); createResidentNode(childNodesByPatternList); createResidentNode(itemsRoot); if (jmxManager != null) { SecurityHelper.doPrivilegedAction(new PrivilegedAction() { public Void run() { jmxManager.registerAllMBeans(); return null; } } this.initialized = true; } /** * {@inheritDoc} */ public void start() { // To prevent any timeout replication during the initialization of a JCR in a // cluster environment we create and start the cache only during the starting phase init(); } /** * {@inheritDoc} */ public void stop() { if (jmxManager != null) { SecurityHelper.doPrivilegedAction(new PrivilegedAction() { public Void run() { jmxManager.unregisterAllMBeans(); return null; } }); } if (shareable) { // The cache cannot be stopped since it can be shared so we evict the root node instead cache.getNode(itemsRoot).setResident(false); cache.evict(itemsRoot, true); cache.getRegion(itemsRoot, false).processEvictionQueues(); cache.getNode(refRoot).setResident(false);; cache.evict(refRoot, true); cache.getRegion(refRoot, false).processEvictionQueues(); cache.getNode(childNodes).setResident(false);; cache.evict(childNodes, true); cache.getRegion(childNodes, false).processEvictionQueues(); cache.getNode(childProps).setResident(false);; cache.evict(childProps, true); cache.getRegion(childProps, false).processEvictionQueues(); cache.getNode(childNodesList).setResident(false); cache.evict(childNodesList, true); cache.getRegion(childNodesList, false).processEvictionQueues(); cache.getNode(childPropsList).setResident(false); cache.evict(childPropsList, true); cache.getRegion(childPropsList, false).processEvictionQueues(); cache.getNode(childNodesByPageList).setResident(false); cache.evict(childNodesByPageList, true); cache.getRegion(childNodesByPageList, false).processEvictionQueues(); cache.getNode(childNodesByPatternList).setResident(false); cache.evict(childNodesByPatternList, true); cache.getRegion(childNodesByPatternList, false).processEvictionQueues(); cache.getNode(childPropsByPatternList).setResident(false); cache.evict(childPropsByPatternList, true); cache.getRegion(childPropsByPatternList, false).processEvictionQueues(); } cache.stop(); } /** * Checks if node with give FQN not exists and creates resident node. * @param fqn */ protected void createResidentNode(Fqn fqn) { Node cacheRoot = cache.getRoot(); if (!cacheRoot.hasChild(fqn)) { cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true); cacheRoot.addChild(fqn).setResident(true); } else { cache.getNode(fqn).setResident(true); } } protected static String readJBCConfig(final WorkspaceEntry wsConfig) throws RepositoryConfigurationException { if (wsConfig.getCache() != null) { { return wsConfig.getCache().getParameterValue(JBOSSCACHE_CONFIG); } else { throw new RepositoryConfigurationException("Cache configuration not found"); } } /** * Return TransactionManager used by JBossCache backing the JCR cache. * * @return TransactionManager */ public TransactionManager getTransactionManager() { return cache.getTransactionManager(); } /** * {@inheritDoc} */ public void put(ItemData item) { // There is different commit processing for NullNodeData and ordinary ItemData if (item instanceof NullItemData) { putNullItem((NullItemData)item); return; } boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (item.isNode()) { putNode((NodeData)item, ModifyChildOption.NOT_MODIFY); } else { putProperty((PropertyData)item, ModifyChildOption.NOT_MODIFY); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void remove(ItemData item) { removeItem(item); } /** * {@inheritDoc} */ public void onSaveItems(final ItemStateChangesLog itemStates) { // if something happen we will rollback changes boolean rollback = true; try { cache.beginTransaction(); for (ItemState state : itemStates.getAllStates()) { if (state.isAdded()) { if (state.isPersisted()) { putItem(state.getData()); } } else if (state.isUpdated()) { if (state.isPersisted()) { // There was a problem with removing a list of samename siblings in on transaction, // so putItemInBufferedCache(..) and updateInBufferedCache(..) used instead put(..) and update (..) methods. ItemData prevItem = putItemInBufferedCache(state.getData()); if (prevItem != null && state.isNode()) { // nodes reordered, if previous is null it's InvalidItemState case updateInBuffer((NodeData)state.getData(), (NodeData)prevItem); } } } else if (state.isDeleted()) { removeItem(state.getData()); } else if (state.isRenamed()) { putItem(state.getData()); } else if (state.isPathChanged()) { * updateTreePath(state.getOldPath(), state.getData().getQPath(), null); } else if (state.isMixinChanged()) { if (state.isPersisted()) { // update subtree ACLs updateMixin((NodeData)state.getData()); } } } cache.commitTransaction(); rollback = false; } finally { if (rollback) { cache.rollbackTransaction(); } } } /** * {@inheritDoc} */ public void addChildNodes(NodeData parent, List childs) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (childs.size() > 0) { Set set = new HashSet(); for (NodeData child : childs) { putNode(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, set); } else { // cache fact of empty childs list cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, new HashSet()); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildNodesByPage(NodeData parent, List childs, int fromOrderNum) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); Fqn fqn = makeChildListFqn(childNodesByPageList, parent.getIdentifier()); Map> pages = (Map>)cache.get(fqn, ITEM_LIST); if (pages == null) { pages = new HashMap>(); } if (childs.size() > 0) { Set set = new HashSet(); for (NodeData child : childs) { putNode(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } pages.put(fromOrderNum, set); cache.put(fqn, ITEM_LIST, pages); } else { // cache fact of empty childs list pages.put(fromOrderNum, new HashSet()); cache.put(fqn, ITEM_LIST, pages); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildNodes(NodeData parent, QPathEntryFilter pattern, List childs) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); Fqn fqn = makeChildFqn(childNodesByPatternList, parent.getIdentifier(), pattern.getQPathEntry()); if (childs.size() > 0) { Set set = new HashSet(); for (NodeData child : childs) { putNode(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.putIfAbsent(fqn, PATTERN_OBJ, pattern); cache.putIfAbsent(fqn, ITEM_LIST, set); } else { // cache fact of empty childs list cache.putIfAbsent(fqn, ITEM_LIST, new HashSet()); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildProperties(NodeData parent, List childs) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (childs.size() > 0) { // add all new Set set = new HashSet(); for (PropertyData child : childs) { putProperty(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.putIfAbsent(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, set); } else { LOG.warn("Empty properties list cached " + (parent != null ? parent.getQPath().getAsString() : parent)); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildProperties(NodeData parent, QPathEntryFilter pattern, List childProperties) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (childProperties.size() > 0) { // add all new Set set = new HashSet(); for (PropertyData child : childProperties) { putProperty(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } Fqn fqn = makeChildFqn(childPropsByPatternList, parent.getIdentifier(), pattern.getQPathEntry()); cache.putIfAbsent(fqn, PATTERN_OBJ, pattern); cache.putIfAbsent(fqn, ITEM_LIST, set); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildPropertiesList(NodeData parent, List childProperties) { } /** * {@inheritDoc} */ public ItemData get(String parentId, QPathEntry name) { return get(parentId, name, ItemType.UNKNOWN); } /** * {@inheritDoc} */ public ItemData get(String parentId, QPathEntry name, ItemType itemType) { return getFromCacheByPath.run(parentId, name, itemType); } /** * {@inheritDoc} */ public ItemData get(String id) { return getFromCacheById.run(id); } /** * {@inheritDoc} */ public List getChildNodes(final NodeData parent) { return getChildNodes.run(parent); } /** * {@inheritDoc} */ public List getChildNodesByPage(final NodeData parent, final int fromOrderNum) { final Map> pages = (Map>)cache .get(makeChildListFqn(childNodesByPageList, parent.getIdentifier()), ITEM_LIST); if (pages == null) { return null; } Set set = pages.get(fromOrderNum); if (set == null) { return null; } final List childs = new ArrayList(); for (Object child : set) { NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (node == null) { return null; } childs.add(node); } // order children by orderNumber, as HashSet returns children in other order Collections.sort(childs, new NodesOrderComparator()); return childs; } /** * {@inheritDoc} */ public List getChildNodes(final NodeData parent, final QPathEntryFilter pattern) { // empty Set marks that there is no child nodes // get list of children uuids final Set set = (Set)cache.get(makeChildFqn(childNodesByPatternList, parent.getIdentifier(), pattern.getQPathEntry()), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { cache.setLocal(false); NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (node == null) { return null; } /** childs.add(node); } // order children by orderNumber, as HashSet returns children in other order Collections.sort(childs, new NodesOrderComparator()); return childs; } else { return null; } } /** * {@inheritDoc} */ public int getChildNodesCount(NodeData parent) { return getChildNodesCount.run(parent); } /** * {@inheritDoc} */ public List getChildProperties(NodeData parent) { return getChildProps(parent.getIdentifier(), true); } /** * {@inheritDoc} */ public List getChildProperties(NodeData parent, QPathEntryFilter pattern) { // get set of property uuids final Set set = (Set)cache.get(makeChildFqn(childPropsByPatternList, parent.getIdentifier(), pattern.getQPathEntry()), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { PropertyData prop = (PropertyData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (prop == null || prop instanceof NullItemData) { return null; } if (prop.getValues().size() <= 0) { // don't return list of empty-valued props (but listChildProperties() can) return null; } childs.add(prop); } return childs; } else { return null; } } /** * {@inheritDoc} */ public List listChildProperties(NodeData parent) { return getChildProps(parent.getIdentifier(), false); } /** * {@inheritDoc} */ public List getReferencedProperties(String identifier) { return getReferencedProperties.run(identifier); } /** * {@inheritDoc} */ public void addReferencedProperties(String identifier, List refProperties) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); Set set = new HashSet(); for (PropertyData prop : refProperties) { putProperty(prop, ModifyChildOption.NOT_MODIFY); set.add(prop.getIdentifier()); } cache.putIfAbsent(makeRefFqn(identifier), ITEM_LIST, set); } finally if (!inTransaction) { dedicatedTxCommit(); } } } * Internal get child properties. * * @param parentId String * @param withValue boolean, if true only "full" Propeties can be returned * @return List of PropertyData */ protected List getChildProps(String parentId, boolean withValue) { return getChildProps.run(parentId, withValue); } /** * {@inheritDoc} */ public long getSize() { return getSize.run(); } /** * Evaluates the total amount of sub-nodes that the given node contains */ private static long numNodes(Node n) { long count = 1;// for n if (n != null) { for (Node child : n.getChildren()) { count += numNodes(child); } } return count; } /** * {@inheritDoc} */ public boolean isEnabled() { return enabled && initialized; } /** * {@inheritDoc} */ public boolean isPatternSupported() { return true; } /** * {@inheritDoc} */ public boolean isChildNodesByPageSupported() { return true; } // non-public members /** * Make Item absolute Fqn, i.e. /$ITEMS/itemID. * * @param itemId String * @return Fqn */ protected Fqn makeItemFqn(String itemId) { return Fqn.fromRelativeElements(itemsRoot, itemId); } /** * Make Item absolute Fqn, i.e. /$REF/itemID. * * @param itemId String * @return Fqn */ protected Fqn makeRefFqn(String itemId) { return Fqn.fromRelativeElements(refRoot, itemId); } /** * Make child Item absolute Fqn, i.e. /root/parentId/childName. * * @param root Fqn * @param parentId String * @param childName QPathEntry * @return Fqn */ protected Fqn makeChildFqn(Fqn root, String parentId, QPathEntry childName) { return Fqn.fromRelativeElements(root, parentId, childName.getAsString(true)); } /** * Make child Item absolute Fqn, i.e. /root/parentId/childName. * * @param root Fqn * @param parentId String * @param childName String * @return Fqn */ protected Fqn makeChildFqn(Fqn root, String parentId, String childName) { return Fqn.fromRelativeElements(root, parentId, childName); } /** * Make child node parent absolute Fqn, i.e. /root/itemId. * @param root Fqn * @param parentId String * @return Fqn */ protected Fqn makeChildListFqn(Fqn root, String parentId) { return Fqn.fromRelativeElements(root, parentId); } /** * Gets item data from cache by item identifier. */ protected ItemData getFromCacheById(String id) { // NullNodeData with id may be stored as ordinary NodeData or PropertyData return (ItemData)cache.get(makeItemFqn(id), ITEM_DATA); } /** * Internal put Item. * * @param item ItemData, new data to put in the cache * @return ItemData, previous data or null */ protected ItemData putItem(ItemData item) { if (item.isNode()) { return putNode((NodeData)item, ModifyChildOption.MODIFY); } else { return putProperty((PropertyData)item, ModifyChildOption.MODIFY); } } protected ItemData putItemInBufferedCache(ItemData item) { if (item.isNode()) { return putNodeInBufferedCache((NodeData)item, ModifyChildOption.MODIFY); } else { return putProperty((PropertyData)item, ModifyChildOption.MODIFY); } } /** * Internal put Node. * * @param node, NodeData, new data to put in the cache * @return NodeData, previous data or null */ protected ItemData putNode(NodeData node, ModifyChildOption modifyListsOfChild) { // if not a root node if (node.getParentIdentifier() != null) { // add in CHILD_NODES cache.put( makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath() .getEntries().length - 1]), ITEM_ID, node.getIdentifier(), modifyListsOfChild == ModifyChildOption.NOT_MODIFY); if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY) { cache.addToPatternList(makeChildListFqn(childNodesByPatternList, node.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, node); cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); cache.removeNode(makeChildListFqn(childNodesByPageList, node.getParentIdentifier())); } } // add in ITEMS return (ItemData) cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node, modifyListsOfChild == ModifyChildOption.NOT_MODIFY); } /** * Internal put NullNode. * * @param item, NullItemData, new data to put in the cache */ protected void putNullItem(NullItemData item) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (!item.getIdentifier().equals(NullItemData.NULL_ID)) { //put in $ITEMS cache.putIfAbsent(makeItemFqn(item.getIdentifier()), ITEM_DATA, item); } else if (item.getName() != null && item.getParentIdentifier() != null) { if (item.isNode()) { // put in $CHILD_NODES * @param node NodeData cache.putIfAbsent(makeChildFqn(childNodes, item.getParentIdentifier(), item.getName()), ITEM_ID, NullItemData.NULL_ID); } else { // put in $CHILD_PROPERTIES cache.putIfAbsent(makeChildFqn(childProps, item.getParentIdentifier(), item.getName()), ITEM_ID, NullItemData.NULL_ID); } } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption modifyListsOfChild) { // if not a root node if (node.getParentIdentifier() != null) { // add in CHILD_NODES cache.put(makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath() .getEntries().length - 1]), ITEM_ID, node.getIdentifier()); if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY) { cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node .getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); } } // add in ITEMS // NullNodeData must never be returned inside internal cache operations. ItemData returnedData = (ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node); return (returnedData instanceof NullItemData) ? null : returnedData; } /** * Internal put Property. * * @param node, PropertyData, new data to put in the cache * @return PropertyData, previous data or null */ protected PropertyData putProperty(PropertyData prop, ModifyChildOption modifyListsOfChild) { // add in CHILD_PROPS cache.put(makeChildFqn(childProps, prop.getParentIdentifier(), prop.getQPath().getEntries()[prop.getQPath() .getEntries().length - 1]), ITEM_ID, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.NOT_MODIFY); if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY) { cache.addToPatternList(makeChildListFqn(childPropsByPatternList, prop.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, prop); cache.addToList(makeChildListFqn(childPropsList, prop.getParentIdentifier()), ITEM_LIST, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); } // add referenced property if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY && prop.getType() == PropertyType.REFERENCE) { List lData = prop.getValues(); for (int i = 0, length = lData.size(); i < length; i++) { ValueData vdata = lData.get(i); String nodeIdentifier = null; try { nodeIdentifier = new String(vdata.getAsByteArray(), Constants.DEFAULT_ENCODING); } catch (IllegalStateException e) { // Do nothing. Never happens. } catch (IOException e) { // Do nothing. Never happens. } cache.addToList(makeRefFqn(nodeIdentifier), ITEM_LIST, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); } } // add in ITEMS // NullItemData must never be returned inside internal cache operations. ItemData returnedData = (ItemData) cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop, modifyListsOfChild == ModifyChildOption.NOT_MODIFY); return (returnedData instanceof NullItemData) ? null : (PropertyData) returnedData; } protected void removeItem(ItemData item) { if (item.isNode()) { if (item.getParentIdentifier() != null) { // if not a root node // remove from CHILD_NODES of parent cache.removeNode(makeChildFqn(childNodes, item.getParentIdentifier(), item.getQPath().getEntries()[item .getQPath().getEntries().length - 1])); // remove from CHILD_NODES_LIST of parent cache.removeFromList(makeChildListFqn(childNodesList, item.getParentIdentifier()), ITEM_LIST, item .getIdentifier()); // remove from CHILD_NODES_BY_PATTERN_LIST of parent cache.removeFromPatternList(makeChildListFqn(childNodesByPatternList, item.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, item); // remove from CHILD_NODES_BY_PAGE_LIST of parent cache.removeNode(makeChildListFqn(childNodesByPageList, item.getParentIdentifier())); } // remove from CHILD_NODES as parent cache.removeNode(makeChildListFqn(childNodes, item.getIdentifier())); // remove from CHILD_NODES_LIST as parent cache.removeNode(makeChildListFqn(childNodesList, item.getIdentifier())); // remove from CHILD_PROPS as parent cache.removeNode(makeChildListFqn(childProps, item.getIdentifier())); // remove from CHILD_PROPS_LIST as parent cache.removeNode(makeChildListFqn(childPropsList, item.getIdentifier())); // remove from CHILD_NODES_BY_PAGE_LIST as parent cache.removeNode(makeChildListFqn(childNodesByPageList, item.getIdentifier())); // remove from CHILD_NODES_BY_PATTERN_LIST as parent cache.removeNode(makeChildListFqn(childNodesByPatternList, item.getIdentifier())); // remove from CHILD_PROPS_BY_PATTERN_LIST as parent cache.removeNode(makeChildListFqn(childPropsByPatternList, item.getIdentifier())); cache.removeNode(makeRefFqn(item.getIdentifier())); } else { // remove from CHILD_PROPS cache.removeNode(makeChildFqn(childProps, item.getParentIdentifier(), item.getQPath().getEntries()[item .getQPath().getEntries().length - 1])); // remove from CHILD_PROPS_LIST cache.removeFromList(makeChildListFqn(childPropsList, item.getParentIdentifier()), ITEM_LIST, item .getIdentifier()); cache.removeFromPatternList(makeChildListFqn(childPropsByPatternList, item.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, item); } // remove from ITEMS cache.removeNode(makeItemFqn(item.getIdentifier())); } /** * Update Node's mixin and ACL. * * @param node NodeData */ protected void updateMixin(NodeData node) { NodeData prevData = (NodeData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node); // prevent update NullNodeData if (prevData != null && !(prevData instanceof NullItemData)) { // do update ACL if needed if (prevData.getACL() == null || !prevData.getACL().equals(node.getACL())) { updateChildsACL(node.getIdentifier(), node.getACL()); } } else if (LOG.isDebugEnabled()) { if (inheritACL LOG.debug("Previous NodeData not found for mixin update " + node.getQPath().getAsString()); } } /** * This method duplicate update method, except using getFromBuffer inside. * * @param prevNode NodeData */ protected void updateInBuffer(final NodeData node, final NodeData prevNode) { // I expect that NullNodeData will never update existing NodeData. // get previously cached NodeData and using its name remove child on the parent Fqn prevFqn = makeChildFqn(childNodes, node.getParentIdentifier(), prevNode.getQPath().getEntries()[prevNode.getQPath() .getEntries().length - 1]); if (node.getIdentifier().equals(cache.getFromBuffer(prevFqn, ITEM_ID))) { // it's same-name siblings re-ordering, delete previous child if (!cache.removeNode(prevFqn) && LOG.isDebugEnabled()) { LOG.debug("Node not extists as a child but update asked " + node.getQPath().getAsString()); } } // node and prevNode are not NullNodeDatas // update childs paths if index changed int nodeIndex = node.getQPath().getEntries()[node.getQPath().getEntries().length - 1].getIndex(); int prevNodeIndex = prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1].getIndex(); if (nodeIndex != prevNodeIndex) { // its a samename reordering updateTreePath(prevNode.getQPath(), node.getQPath(), null); // don't change ACL, it's same parent } } /** * Check all items in cache - is it descendant of prevRootPath, and update path according newRootPath. * * @param prevRootPath * @param newRootPath * @param acl */ protected void updateTreePath(final QPath prevRootPath, final QPath newRootPath, final AccessControlList acl) { boolean inheritACL = acl != null; // check all ITEMS in cache Node items = cache.getNode(itemsRoot); Set childrenNames = items.getChildrenNames(); Iterator namesIt = childrenNames.iterator(); while (namesIt.hasNext()) { String id = (String)namesIt.next(); ItemData data = (ItemData)cache.get(makeItemFqn(id), ITEM_DATA); // check is this descendant of prevRootPath QPath nodeQPath = data.getQPath(); if (nodeQPath != null && nodeQPath.isDescendantOf(prevRootPath)) { //make relative path QPathEntry[] relativePath = null; try { relativePath = nodeQPath.getRelPath(nodeQPath.getDepth() - prevRootPath.getDepth()); } catch (IllegalPathException e) { // Do nothing. Never happens. } // make new path - no matter node or property QPath newPath = QPath.makeChildPath(newRootPath, relativePath); if (data.isNode()) { // update node NodeData prevNode = (NodeData)data; NodeData newNode = new PersistedNodeData(prevNode.getIdentifier(), newPath, prevNode.getParentIdentifier(), prevNode.getPersistedVersion(), prevNode.getOrderNumber(), prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), inheritACL ? acl : prevNode.getACL()); // update this node cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode); } else { //update property PropertyData prevProp = (PropertyData)data; && (prevProp.getQPath().getName().equals(Constants.EXO_PERMISSIONS) || prevProp.getQPath().getName() .equals(Constants.EXO_OWNER))) { inheritACL = false; } PropertyData newProp = new PersistedPropertyData(prevProp.getIdentifier(), newPath, prevProp.getParentIdentifier(), prevProp.getPersistedVersion(), prevProp.getType(), prevProp.isMultiValued(), prevProp.getValues()); cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp); } } } } /** * Update child Nodes ACLs. * * @param parentId String - root node id of JCR subtree. * @param acl AccessControlList */ protected void updateChildsACL(final String parentId, final AccessControlList acl) { loop: for (Iterator iter = new ChildNodesIterator(parentId); iter.hasNext();) { NodeData prevNode = iter.next(); // is ACL changes on this node (i.e. ACL inheritance broken) for (InternalQName mixin : prevNode.getMixinTypeNames()) { if (mixin.equals(Constants.EXO_PRIVILEGEABLE) || mixin.equals(Constants.EXO_OWNEABLE)) { continue loop; } } // recreate with new path for child Nodes only TransientNodeData newNode = new TransientNodeData(prevNode.getQPath(), prevNode.getIdentifier(), prevNode.getPersistedVersion(), prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode .getParentIdentifier(), acl); // update this node cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode); // update childs recursive updateChildsACL(newNode.getIdentifier(), acl); } } public void beginTransaction() { cache.beginTransaction(); } public void commitTransaction() { cache.commitTransaction(); } public void rollbackTransaction() { cache.rollbackTransaction(); } /** * {@inheritDoc} */ public boolean isTXAware() { return true; } /** *
        • NOT_MODIFY - node(property) is not added to the parent's list * (no persistent changes performed, cache used as cache)
        • *
        • MODIFY - node(property) is added to the parent's list if parent in the cache * (new item is added to persistent, add to list if it is present)
        • *
        • FORCE_MODIFY - node(property) is added to the parent's list anyway * (when list is read from DB, forcing write)
        • */ private enum ModifyChildOption { NOT_MODIFY, MODIFY, FORCE_MODIFY } /** * Allows to commit the cache changes in a dedicated XA Tx in order to avoid potential * deadlocks */ private void dedicatedTxCommit() { // Ensure that the commit is done in a dedicated tx to avoid deadlock due // to global XA Tx commitTransaction.run(); } /** * {@inheritDoc} */ public void backup(File storageDir) throws BackupException { } /** * {@inheritDoc} */ @Managed @ManagedDescription("Remove all the existing items from the cache") public void clean() throws BackupException { cleanCache(); } /** * {@inheritDoc} */ public DataRestore getDataRestorer(DataRestoreContext context) throws BackupException { return new DataRestore() { /** * {@inheritDoc} */ public void clean() throws BackupException { cleanCache(); } /** * {@inheritDoc} */ public void restore() throws BackupException { } /** * {@inheritDoc} */ public void commit() throws BackupException { } /** * {@inheritDoc} */ public void rollback() throws BackupException { } /** * {@inheritDoc} */ public void close() throws BackupException { } }; } /** * Clean all cache data. */ private void cleanCache() { if (cache.getCacheStatus() == CacheStatus.STARTED) { cache.beginTransaction(); cache.removeNode(itemsRoot); cache.removeNode(refRoot); cache.removeNode(childNodes); cache.removeNode(childProps); cache.removeNode(childNodesList); cache.removeNode(childPropsList); cache.removeNode(childNodesByPageList); cache.removeNode(childNodesByPatternList); cache.removeNode(childPropsByPatternList); cache.commitTransaction(); createResidentNode(childNodes); createResidentNode(refRoot); createResidentNode(childNodesList); createResidentNode(childProps); createResidentNode(childPropsList); createResidentNode(childNodesByPageList); createResidentNode(childNodesByPatternList); createResidentNode(childPropsByPatternList); createResidentNode(itemsRoot); } } /** * {@inheritDoc} */ public void addListener(WorkspaceStorageCacheListener listener) { // As the listeners in JBC really slow down the whole application, we decided to disable // the bloom filters in case of JBC throw new UnsupportedOperationException("The cache listeners are not supported by the JBossCacheWorkspaceStorageCache"); } /** * {@inheritDoc} */ public void removeListener(WorkspaceStorageCacheListener listener) { // As the listeners in JBC really slow down the whole application, we decided to disable // the bloom filters in case of JBC throw new UnsupportedOperationException("The cache listeners are not supported by the JBossCacheWorkspaceStorageCache"); } /** * Actions that are not supposed to be called within a transaction * * Created by The eXo Platform SAS * Author : Nicolas Filotto * nicolas.filotto@exoplatform.com * 21 janv. 2010 */ protected abstract class CacheActionNonTxAware extends ActionNonTxAware { /** * @see org.exoplatform.services.transaction.ActionNonTxAware#getTransactionManager() */ protected TransactionManager getTransactionManager() { return JBossCacheWorkspaceStorageCache.this.getTransactionManager(); } } } >>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

Solution content
   {
/*
 * 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.dataflow.persistent.jbosscache;

import org.exoplatform.commons.utils.SecurityHelper;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.container.configuration.ConfigurationManager;
import org.exoplatform.management.annotations.Managed;
import org.exoplatform.management.annotations.ManagedDescription;
import org.exoplatform.services.jcr.access.AccessControlList;
import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.exoplatform.services.jcr.config.WorkspaceEntry;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener;
import org.exoplatform.services.jcr.datamodel.IllegalPathException;
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.NullItemData;
import org.exoplatform.services.jcr.datamodel.NullNodeData;
import org.exoplatform.services.jcr.datamodel.NullPropertyData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPath;
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.backup.BackupException;
import org.exoplatform.services.jcr.impl.backup.Backupable;
import org.exoplatform.services.jcr.impl.backup.DataRestore;
import org.exoplatform.services.jcr.impl.backup.rdbms.DataRestoreContext;
import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory;
import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory.CacheType;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.transaction.ActionNonTxAware;
import org.exoplatform.services.transaction.TransactionService;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheStatus;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.config.Configuration.CacheMode;
import org.jboss.cache.config.EvictionRegionConfig;
import org.jboss.cache.eviction.ExpirationAlgorithmConfig;
import org.jboss.cache.jmx.JmxRegistrationManager;
import org.picocontainer.Startable;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.transaction.TransactionManager;

/**
 * Created by The eXo Platform SAS.

* * Cache based on JBossCache.

* *

    *
  • cache transparent: or item cached or not, we should not generate "not found" Exceptions
  • *
  • cache consists of next resident nodes: *
      *
    • /$ITEMS - stores items by Id (i.e. /$ITEMS/itemId)
    • *
    • /$CHILD_NODES, /$CHILD_PROPS - stores items by parentId and name (i.e. /$CHILD_NODES/parentId/childName.$ITEM_ID)
    • *
    • /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST - stores child list by parentId and child Id * (i.e. /$CHILD_NODES_LIST/parentId.lists = serialized Set) * * *
    • all child properties/nodes lists should be evicted from parent at same time * i.e. for /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST we need customized eviction policy (EvictionActionPolicy) to evict * whole list on one of childs eviction *
    • * * *

      * Current state notes (subject of change): *

        *
      • cache implements WorkspaceStorageCache, without any stuff about references and locks
      • *
      • transaction style implemented via JBC barches, do with JTA (i.e. via exo's TransactionService + JBoss TM)
      • *
      • we need customized eviction policy (EvictionActionPolicy) for /$CHILD_NODES_LIST, /$CHILD_PROPS_LIST
      • *
      * * @author Peter Nedonosko * @version $Id: JBossCacheWorkspaceStorageCache.java 13869 2008-05-05 08:40:10Z pnedonosko $ */ public class JBossCacheWorkspaceStorageCache implements WorkspaceStorageCache, Startable, Backupable { private static final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.JBossCacheWorkspaceStorageCache"); private final boolean enabled; private final boolean shareable; public static final String JBOSSCACHE_CONFIG = "jbosscache-configuration"; public static final String JBOSSCACHE_EXPIRATION = "jbosscache-expiration-time"; /** * Indicate whether the JBoss Cache instance used can be shared with other caches */ public static final String JBOSSCACHE_SHAREABLE = "jbosscache-shareable"; public static final Boolean JBOSSCACHE_SHAREABLE_DEFAULT = Boolean.FALSE; public static final long JBOSSCACHE_EXPIRATION_DEFAULT = 900000; // 15 minutes public static final String ITEMS = "$ITEMS".intern(); public static final String NULL_ITEMS = "$NULL_ITEMS".intern(); public static final String CHILD_NODES = "$CHILD_NODES".intern(); public static final String CHILD_PROPS = "$CHILD_PROPS".intern(); public static final String CHILD_NODES_LIST = "$CHILD_NODES_LIST".intern(); public static final String CHILD_PROPS_LIST = "$CHILD_PROPS_LIST".intern(); public static final String CHILD_PROPS_BY_PATTERN_LIST = "$CHILD_PROPS_BY_PATTERN_LIST".intern(); public static final String CHILD_NODES_BY_PATTERN_LIST = "$CHILD_NODES_BY_PATTERN_LIST".intern(); public static final String CHILD_NODES_BY_PAGE_LIST = "$CHILD_NODES_BY_PAGE_LIST".intern(); public static final String LOCKS = "$LOCKS".intern(); public static final String REFERENCE = "$REFERENCE".intern(); public static final String ITEM_DATA = "$data".intern(); public static final String ITEM_ID = "$id".intern(); public static final String ITEM_LIST = "$lists".intern(); public static final String PATTERN_OBJ = "$pattern".intern(); protected final BufferedJBossCache cache; protected final Fqn itemsRoot; protected final Fqn refRoot; protected final Fqn childNodes; protected final Fqn childProps; protected final Fqn childNodesList; protected final Fqn childPropsList; protected final Fqn childNodesByPageList; { protected final Fqn childPropsByPatternList; protected final Fqn childNodesByPatternList; protected final Fqn rootFqn; private final CacheActionNonTxAware commitTransaction = new CacheActionNonTxAware() @Override protected Void execute(Void arg) throws RuntimeException { cache.commitTransaction(); return null; } }; private final CacheActionNonTxAware getFromCacheById = new CacheActionNonTxAware() { @Override protected ItemData execute(String id) throws RuntimeException { return getFromCacheById(id); } }; private final CacheActionNonTxAware, NodeData> getChildNodes = new CacheActionNonTxAware, NodeData>() { @Override protected List execute(NodeData parent) throws RuntimeException { // empty Set marks that there is no child nodes // get list of children uuids final Set set = (Set)cache.get(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (node == null) { return null; } childs.add(node); } // order children by orderNumber, as HashSet returns children in other order Collections.sort(childs, new NodesOrderComparator()); return childs; } else { return null; } } }; private final CacheActionNonTxAware getFromCacheByPath = new CacheActionNonTxAware() { @Override protected ItemData execute(Object... args) throws RuntimeException { String parentId = (String)args[0]; QPathEntry name = (QPathEntry)args[1]; ItemType itemType = (ItemType)args[2]; String itemId = null; if (itemType == ItemType.UNKNOWN) { // Try as node first. itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID); if (itemId == null || itemId.equals(NullItemData.NULL_ID)) { // node with such a name is not found or marked as not-exist, so check the properties String propId = (String)cache.get(makeChildFqn(childProps, parentId, name), ITEM_ID); if (propId != null) { itemId = propId; } } } else if (itemType == ItemType.NODE) { itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID); } else { itemId = (String)cache.get(makeChildFqn(childProps, parentId, name), ITEM_ID); } if (itemId != null) if (itemId.equals(NullItemData.NULL_ID)) { if (itemType == ItemType.UNKNOWN || itemType == ItemType.NODE) { return new NullNodeData(); } else { return new NullPropertyData(); } } else { return get(itemId); } } return null; } }; private final CacheActionNonTxAware getChildNodesCount = new CacheActionNonTxAware() { @Override protected Integer execute(NodeData parent) throws RuntimeException { // get list of children uuids final Set set = (Set)cache.get(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST); return set != null ? set.size() : -1; } }; private final CacheActionNonTxAware, Object> getChildProps = new CacheActionNonTxAware, Object>() { @Override protected List execute(Object... args) throws RuntimeException { String parentId = (String)args[0]; boolean withValue = (Boolean)args[1]; // get set of property uuids final Set set = (Set)cache.get(makeChildListFqn(childPropsList, parentId), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { PropertyData prop = (PropertyData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (prop == null || prop instanceof NullItemData) { return null; } if (withValue && prop.getValues().size() <= 0) { // don't return list of empty-valued props (but listChildProperties() can) return null; } childs.add(prop); } return childs; } else { return null; } } }; private final CacheActionNonTxAware, String> getReferencedProperties = new CacheActionNonTxAware, String>() { @Override protected List execute(String identifier) throws RuntimeException { // get set of property uuids final Set set = (Set)cache.get(makeRefFqn(identifier), ITEM_LIST); if (set != null) { final List props = new ArrayList(); for (String propId : set) { PropertyData prop = (PropertyData)cache.get(makeItemFqn(propId), ITEM_DATA); if (prop == null || prop instanceof NullItemData) { return null; } // add property as many times as has referenced values List lData = prop.getValues(); for (int i = 0, length = lData.size(); i < length; i++) { ValueData vdata = lData.get(i); try { if (new String(vdata.getAsByteArray(), Constants.DEFAULT_ENCODING).equals(identifier)) { props.add(prop); } } catch (IllegalStateException e) { // Do not nothing. } catch (IOException e) { // Do not nothing. } } } return props; } else { return null; } } }; private final CacheActionNonTxAware getSize = new CacheActionNonTxAware() { @Override protected Long execute(Void arg) throws RuntimeException { // Total number of JBC nodes in the cache - the total amount of resident nodes return numNodes(cache.getNode(rootFqn)) - 10; } }; /** * Indicates whether the cache has already been initialized or not */ protected volatile boolean initialized; private JmxRegistrationManager jmxManager; /** * Node order comparator for getChildNodes(). */ class NodesOrderComparator implements Comparator { /** * {@inheritDoc} */ public int compare(NodeData n1, NodeData n2) { return n1.getOrderNumber() - n2.getOrderNumber(); } } class ChildItemsIterator implements Iterator { final Iterator childs; final String parentId; final Fqn root; T next; ChildItemsIterator(Fqn root, String parentId) { this.parentId = parentId; this.root = root; Fqn parentFqn = makeChildListFqn(root, parentId); Node parent = cache.getNode(parentFqn); if (parent != null) { this.childs = cache.getChildrenNames(parentFqn).iterator(); fetchNext(); } else { this.childs = null; this.next = null; } } protected void fetchNext() { if (childs.hasNext()) { // traverse to the first existing or the end of childs T n = null; do { String itemId = (String)cache.get(makeChildFqn(root, parentId, (String)childs.next()), ITEM_ID); if (itemId != null) { n = (T)cache.get(makeItemFqn(itemId), ITEM_DATA); } } while (n == null && childs.hasNext()); next = n; } else { next = null; } } { public boolean hasNext() { return next != null; } public T next() { if (next == null) throw new NoSuchElementException(); } final T current = next; fetchNext(); return current; } public void remove() { throw new IllegalArgumentException("Not implemented"); } } class ChildNodesIterator extends ChildItemsIterator { ChildNodesIterator(String parentId) { super(childNodes, parentId); } @Override public N next() { return super.next(); } } class ChildPropertiesIterator

      extends ChildItemsIterator

      { ChildPropertiesIterator(String parentId) { super(childProps, parentId); } @Override public P next() { return super.next(); } } /** * Cache constructor with eXo TransactionService support. * * @param ctx The container context * @param wsConfig WorkspaceEntry workspace config * @param transactionService TransactionService external transaction service * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(ExoContainerContext ctx, WorkspaceEntry wsConfig, TransactionService transactionService, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { if (wsConfig.getCache() == null) { throw new RepositoryConfigurationException("Cache configuration not found"); } enabled = wsConfig.getCache().isEnabled(); shareable = wsConfig.getCache().getParameterBoolean(JBOSSCACHE_SHAREABLE, JBOSSCACHE_SHAREABLE_DEFAULT).booleanValue(); // create cache using custom factory ExoJBossCacheFactory factory; if (transactionService != null) { factory = new ExoJBossCacheFactory(cfm, transactionService.getTransactionManager()); } else { factory = new ExoJBossCacheFactory(cfm); } // create parent JBossCache instance Cache parentCache = factory.createCache(wsConfig.getCache()); // get all eviction configurations List evictionConfigurations = parentCache.getConfiguration().getEvictionConfig().getEvictionRegionConfigs(); // append and default eviction configuration, since it is not present in region configurations evictionConfigurations.add(parentCache.getConfiguration().getEvictionConfig().getDefaultEvictionRegionConfig()); boolean useExpiration = false; // looking over all eviction configurations till the end or till some expiration algorithm subclass not found. for (EvictionRegionConfig evictionRegionConfig : evictionConfigurations) { if (evictionRegionConfig.getEvictionAlgorithmConfig() instanceof ExpirationAlgorithmConfig) { // force set expiration key to default value in all Expiration configurations (if any) ((ExpirationAlgorithmConfig)evictionRegionConfig.getEvictionAlgorithmConfig()) .setExpirationKeyName(ExpirationAlgorithmConfig.EXPIRATION_KEY); useExpiration = true; } } if (useExpiration) { LOG.info("Using BufferedJBossCache compatible with Expiration algorithm."); } this.rootFqn = Fqn.fromElements(wsConfig.getUniqueName()); parentCache = ExoJBossCacheFactory.getUniqueInstance(CacheType.JCR_CACHE, rootFqn, parentCache, wsConfig.getCache() .getParameterBoolean(JBOSSCACHE_SHAREABLE, JBOSSCACHE_SHAREABLE_DEFAULT).booleanValue()); if (ctx != null) { this.jmxManager = ExoJBossCacheFactory.getJmxRegistrationManager(ctx, parentCache, CacheType.JCR_CACHE); } // if expiration is used, set appropriate factory with with timeout set via configuration (or default one 15minutes) this.cache = new BufferedJBossCache(parentCache, useExpiration, wsConfig.getCache().getParameterTime(JBOSSCACHE_EXPIRATION, JBOSSCACHE_EXPIRATION_DEFAULT)); this.itemsRoot = Fqn.fromRelativeElements(rootFqn, ITEMS); this.refRoot = Fqn.fromRelativeElements(rootFqn, REFERENCE); this.childNodes = Fqn.fromRelativeElements(rootFqn, CHILD_NODES); this.childProps = Fqn.fromRelativeElements(rootFqn, CHILD_PROPS); this.childNodesList = Fqn.fromRelativeElements(rootFqn, CHILD_NODES_LIST); this.childPropsList = Fqn.fromRelativeElements(rootFqn, CHILD_PROPS_LIST); this.childNodesByPageList = Fqn.fromRelativeElements(rootFqn, CHILD_NODES_BY_PAGE_LIST); this.childPropsByPatternList = Fqn.fromRelativeElements(rootFqn, CHILD_PROPS_BY_PATTERN_LIST); this.childNodesByPatternList = Fqn.fromRelativeElements(rootFqn, CHILD_NODES_BY_PATTERN_LIST); if (cache.getConfiguration().getCacheMode() == CacheMode.LOCAL) { // The cache is local so we have no risk to get replication exception // during the initialization phase init(); } } /** * Cache constructor with eXo TransactionService support. * * @param wsConfig WorkspaceEntry workspace config * @param transactionService TransactionService external transaction service * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(WorkspaceEntry wsConfig, TransactionService transactionService, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { this(null, wsConfig, transactionService, cfm); } /** * Cache constructor with JBossCache JTA transaction support. * * @param ctx The container context * @param wsConfig WorkspaceEntry workspace config * @throws RepositoryException if error of initialization * @throws RepositoryConfigurationException if error of configuration */ public JBossCacheWorkspaceStorageCache(ExoContainerContext ctx, WorkspaceEntry wsConfig, ConfigurationManager cfm) throws RepositoryException, RepositoryConfigurationException { this(ctx, wsConfig, null, cfm); } /** * Creates, starts and initialize the cache */ private void init() { if (initialized) { // The cache has already been initialized return; } this.cache.create(); this.cache.start(); createResidentNode(childNodes); createResidentNode(refRoot); createResidentNode(childNodesList); createResidentNode(childProps); createResidentNode(childPropsList); createResidentNode(childNodesByPageList); createResidentNode(childPropsByPatternList); } public Void run() protected static String readJBCConfig(final WorkspaceEntry wsConfig) throws RepositoryConfigurationException { if (wsConfig.getCache() != null) { createResidentNode(childNodesByPatternList); createResidentNode(itemsRoot); if (jmxManager != null) { SecurityHelper.doPrivilegedAction(new PrivilegedAction() { { jmxManager.registerAllMBeans(); return null; } }); } this.initialized = true; } /** * {@inheritDoc} */ public void start() { // To prevent any timeout replication during the initialization of a JCR in a // cluster environment we create and start the cache only during the starting phase init(); } /** * {@inheritDoc} */ public void stop() { if (jmxManager != null) { SecurityHelper.doPrivilegedAction(new PrivilegedAction() { public Void run() { jmxManager.unregisterAllMBeans(); return null; } }); } if (shareable) { // The cache cannot be stopped since it can be shared so we evict the root node instead cache.getNode(itemsRoot).setResident(false); cache.evict(itemsRoot, true); cache.getRegion(itemsRoot, false).processEvictionQueues(); cache.getNode(refRoot).setResident(false);; cache.evict(refRoot, true); cache.getRegion(refRoot, false).processEvictionQueues(); cache.getNode(childNodes).setResident(false);; cache.evict(childNodes, true); cache.getRegion(childNodes, false).processEvictionQueues(); cache.getNode(childProps).setResident(false);; cache.evict(childProps, true); cache.getRegion(childProps, false).processEvictionQueues(); cache.getNode(childNodesList).setResident(false); cache.evict(childNodesList, true); cache.getRegion(childNodesList, false).processEvictionQueues(); cache.getNode(childPropsList).setResident(false); cache.evict(childPropsList, true); cache.getRegion(childPropsList, false).processEvictionQueues(); cache.getNode(childNodesByPageList).setResident(false); cache.evict(childNodesByPageList, true); cache.getRegion(childNodesByPageList, false).processEvictionQueues(); cache.getNode(childNodesByPatternList).setResident(false); cache.evict(childNodesByPatternList, true); cache.getRegion(childNodesByPatternList, false).processEvictionQueues(); cache.getNode(childPropsByPatternList).setResident(false); cache.evict(childPropsByPatternList, true); cache.getRegion(childPropsByPatternList, false).processEvictionQueues(); } cache.stop(); } /** * Checks if node with give FQN not exists and creates resident node. * @param fqn */ protected void createResidentNode(Fqn fqn) { Node cacheRoot = cache.getRoot(); if (!cacheRoot.hasChild(fqn)) { cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true); cacheRoot.addChild(fqn).setResident(true); } else { cache.getNode(fqn).setResident(true); } return wsConfig.getCache().getParameterValue(JBOSSCACHE_CONFIG); } else { throw new RepositoryConfigurationException("Cache configuration not found"); } } /** * Return TransactionManager used by JBossCache backing the JCR cache. * * @return TransactionManager */ public TransactionManager getTransactionManager() { return cache.getTransactionManager(); } /** * {@inheritDoc} */ public void put(ItemData item) { // There is different commit processing for NullNodeData and ordinary ItemData if (item instanceof NullItemData) { putNullItem((NullItemData)item); return; } boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (item.isNode()) { putNode((NodeData)item, ModifyChildOption.NOT_MODIFY); } else { putProperty((PropertyData)item, ModifyChildOption.NOT_MODIFY); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void remove(ItemData item) { removeItem(item); } /** * {@inheritDoc} */ public void onSaveItems(final ItemStateChangesLog itemStates) { // if something happen we will rollback changes boolean rollback = true; try { cache.beginTransaction(); for (ItemState state : itemStates.getAllStates()) { if (state.isAdded()) { if (state.isPersisted()) { putItem(state.getData()); } } else if (state.isUpdated()) { if (state.isPersisted()) { // There was a problem with removing a list of samename siblings in on transaction, // so putItemInBufferedCache(..) and updateInBufferedCache(..) used instead put(..) and update (..) methods. ItemData prevItem = putItemInBufferedCache(state.getData()); if (prevItem != null && state.isNode()) { // nodes reordered, if previous is null it's InvalidItemState case updateInBuffer((NodeData)state.getData(), (NodeData)prevItem); } } } else if (state.isDeleted()) { removeItem(state.getData()); } else if (state.isRenamed()) { putItem(state.getData()); } else if (state.isPathChanged()) { } updateTreePath(state.getOldPath(), state.getData().getQPath(), null); } else if (state.isMixinChanged()) { if (state.isPersisted()) { // update subtree ACLs updateMixin((NodeData)state.getData()); } } } cache.commitTransaction(); rollback = false; } finally { if (rollback) { cache.rollbackTransaction(); } } } /** * {@inheritDoc} */ public void addChildNodes(NodeData parent, List childs) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (childs.size() > 0) { Set set = new HashSet(); for (NodeData child : childs) { putNode(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, set); } else { // cache fact of empty childs list cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, new HashSet()); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildNodesByPage(NodeData parent, List childs, int fromOrderNum) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); Fqn fqn = makeChildListFqn(childNodesByPageList, parent.getIdentifier()); Map> pages = (Map>)cache.get(fqn, ITEM_LIST); if (pages == null) { pages = new HashMap>(); } if (childs.size() > 0) { Set set = new HashSet(); for (NodeData child : childs) { putNode(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } pages.put(fromOrderNum, set); cache.put(fqn, ITEM_LIST, pages); } else { // cache fact of empty childs list pages.put(fromOrderNum, new HashSet()); cache.put(fqn, ITEM_LIST, pages); } } finally { cache.setLocal(false); * {@inheritDoc} */ set.add(child.getIdentifier()); } Fqn fqn = makeChildFqn(childPropsByPatternList, parent.getIdentifier(), pattern.getQPathEntry()); cache.putIfAbsent(fqn, PATTERN_OBJ, pattern); cache.putIfAbsent(fqn, ITEM_LIST, set); if (!inTransaction) { dedicatedTxCommit(); } } } /** public void addChildNodes(NodeData parent, QPathEntryFilter pattern, List childs) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); Fqn fqn = makeChildFqn(childNodesByPatternList, parent.getIdentifier(), pattern.getQPathEntry()); if (childs.size() > 0) { Set set = new HashSet(); for (NodeData child : childs) { putNode(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.putIfAbsent(fqn, PATTERN_OBJ, pattern); cache.putIfAbsent(fqn, ITEM_LIST, set); } else { // cache fact of empty childs list cache.putIfAbsent(fqn, ITEM_LIST, new HashSet()); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildProperties(NodeData parent, List childs) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (childs.size() > 0) { // add all new Set set = new HashSet(); for (PropertyData child : childs) { putProperty(child, ModifyChildOption.NOT_MODIFY); set.add(child.getIdentifier()); } cache.putIfAbsent(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, set); } else { LOG.warn("Empty properties list cached " + (parent != null ? parent.getQPath().getAsString() : parent)); } } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * {@inheritDoc} */ public void addChildProperties(NodeData parent, QPathEntryFilter pattern, List childProperties) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (childProperties.size() > 0) { // add all new Set set = new HashSet(); for (PropertyData child : childProperties) { putProperty(child, ModifyChildOption.NOT_MODIFY); } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } * @param parentId String /** * {@inheritDoc} */ public void addChildPropertiesList(NodeData parent, List childProperties) { } /** * {@inheritDoc} */ public ItemData get(String parentId, QPathEntry name) { return get(parentId, name, ItemType.UNKNOWN); } /** * {@inheritDoc} */ public ItemData get(String parentId, QPathEntry name, ItemType itemType) { return getFromCacheByPath.run(parentId, name, itemType); } /** * {@inheritDoc} */ public ItemData get(String id) { return getFromCacheById.run(id); } /** * {@inheritDoc} */ public List getChildNodes(final NodeData parent) { return getChildNodes.run(parent); } /** * {@inheritDoc} */ public List getChildNodesByPage(final NodeData parent, final int fromOrderNum) { final Map> pages = (Map>)cache .get(makeChildListFqn(childNodesByPageList, parent.getIdentifier()), ITEM_LIST); if (pages == null) { return null; } Set set = pages.get(fromOrderNum); if (set == null) { return null; } final List childs = new ArrayList(); for (Object child : set) { NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (node == null) { return null; } childs.add(node); } // order children by orderNumber, as HashSet returns children in other order Collections.sort(childs, new NodesOrderComparator()); return childs; } /** * {@inheritDoc} */ public List getChildNodes(final NodeData parent, final QPathEntryFilter pattern) { // empty Set marks that there is no child nodes // get list of children uuids final Set set = (Set)cache.get(makeChildFqn(childNodesByPatternList, parent.getIdentifier(), pattern.getQPathEntry()), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (node == null) { return null; } childs.add(node); } // order children by orderNumber, as HashSet returns children in other order Collections.sort(childs, new NodesOrderComparator()); return childs; } else { return null; } } /** * {@inheritDoc} */ public int getChildNodesCount(NodeData parent) { return getChildNodesCount.run(parent); } /** * {@inheritDoc} */ public List getChildProperties(NodeData parent) { return getChildProps(parent.getIdentifier(), true); } /** * {@inheritDoc} */ public List getChildProperties(NodeData parent, QPathEntryFilter pattern) { // get set of property uuids final Set set = (Set)cache.get(makeChildFqn(childPropsByPatternList, parent.getIdentifier(), pattern.getQPathEntry()), ITEM_LIST); if (set != null) { final List childs = new ArrayList(); for (Object child : set) { PropertyData prop = (PropertyData)cache.get(makeItemFqn((String)child), ITEM_DATA); if (prop == null || prop instanceof NullItemData) { return null; } if (prop.getValues().size() <= 0) { // don't return list of empty-valued props (but listChildProperties() can) return null; } childs.add(prop); } return childs; } else { return null; } } /** * {@inheritDoc} */ public List listChildProperties(NodeData parent) { return getChildProps(parent.getIdentifier(), false); } /** * {@inheritDoc} */ public List getReferencedProperties(String identifier) { return getReferencedProperties.run(identifier); } /** * {@inheritDoc} */ public void addReferencedProperties(String identifier, List refProperties) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); Set set = new HashSet(); for (PropertyData prop : refProperties) { putProperty(prop, ModifyChildOption.NOT_MODIFY); set.add(prop.getIdentifier()); } cache.putIfAbsent(makeRefFqn(identifier), ITEM_LIST, set); } finally { cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } /** * Internal get child properties. * { * @param withValue boolean, if true only "full" Propeties can be returned * @return List of PropertyData */ protected List getChildProps(String parentId, boolean withValue) { return getChildProps.run(parentId, withValue); } /** * {@inheritDoc} */ public long getSize() { return getSize.run(); } /** * Evaluates the total amount of sub-nodes that the given node contains */ private static long numNodes(Node n) { long count = 1;// for n if (n != null) { for (Node child : n.getChildren()) { count += numNodes(child); } } return count; } /** * {@inheritDoc} */ public boolean isEnabled() { return enabled && initialized; } /** * {@inheritDoc} */ public boolean isPatternSupported() { return true; } /** * {@inheritDoc} */ public boolean isChildNodesByPageSupported() { return true; } // non-public members /** * Make Item absolute Fqn, i.e. /$ITEMS/itemID. * * @param itemId String * @return Fqn */ protected Fqn makeItemFqn(String itemId) { return Fqn.fromRelativeElements(itemsRoot, itemId); } /** * Make Item absolute Fqn, i.e. /$REF/itemID. * * @param itemId String * @return Fqn */ protected Fqn makeRefFqn(String itemId) { return Fqn.fromRelativeElements(refRoot, itemId); } /** * Make child Item absolute Fqn, i.e. /root/parentId/childName. * * @param root Fqn * @param parentId String * @param childName QPathEntry * @return Fqn */ protected Fqn makeChildFqn(Fqn root, String parentId, QPathEntry childName) { return Fqn.fromRelativeElements(root, parentId, childName.getAsString(true)); } /** * Make child Item absolute Fqn, i.e. /root/parentId/childName. * * @param root Fqn * @param parentId String * @param childName String * @return Fqn */ protected Fqn makeChildFqn(Fqn root, String parentId, String childName) { return Fqn.fromRelativeElements(root, parentId, childName); } /** * Make child node parent absolute Fqn, i.e. /root/itemId. * * @param root Fqn * @param parentId String * @return Fqn */ protected Fqn makeChildListFqn(Fqn root, String parentId) { return Fqn.fromRelativeElements(root, parentId); } /** * Gets item data from cache by item identifier. */ protected ItemData getFromCacheById(String id) { // NullNodeData with id may be stored as ordinary NodeData or PropertyData return (ItemData)cache.get(makeItemFqn(id), ITEM_DATA); } /** * Internal put Item. * * @param item ItemData, new data to put in the cache * @return ItemData, previous data or null */ protected ItemData putItem(ItemData item) { if (item.isNode()) { return putNode((NodeData)item, ModifyChildOption.MODIFY); } else { return putProperty((PropertyData)item, ModifyChildOption.MODIFY); } } protected ItemData putItemInBufferedCache(ItemData item) { if (item.isNode()) { return putNodeInBufferedCache((NodeData)item, ModifyChildOption.MODIFY); } else { return putProperty((PropertyData)item, ModifyChildOption.MODIFY); } } /** * Internal put Node. * * @param node, NodeData, new data to put in the cache * @return NodeData, previous data or null */ protected ItemData putNode(NodeData node, ModifyChildOption modifyListsOfChild) { // if not a root node if (node.getParentIdentifier() != null) { // add in CHILD_NODES cache.put( makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath() .getEntries().length - 1]), ITEM_ID, node.getIdentifier(), modifyListsOfChild == ModifyChildOption.NOT_MODIFY); if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY) { cache.addToPatternList(makeChildListFqn(childNodesByPatternList, node.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, node); cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); cache.removeNode(makeChildListFqn(childNodesByPageList, node.getParentIdentifier())); } } // add in ITEMS return (ItemData) cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node, modifyListsOfChild == ModifyChildOption.NOT_MODIFY); } /** * Internal put NullNode. * * @param item, NullItemData, new data to put in the cache */ protected void putNullItem(NullItemData item) { boolean inTransaction = cache.isTransactionActive(); try { if (!inTransaction) { cache.beginTransaction(); } cache.setLocal(true); if (!item.getIdentifier().equals(NullItemData.NULL_ID)) { //put in $ITEMS cache.putIfAbsent(makeItemFqn(item.getIdentifier()), ITEM_DATA, item); } else if (item.getName() != null && item.getParentIdentifier() != null) { if (item.isNode()) { // put in $CHILD_NODES cache.putIfAbsent(makeChildFqn(childNodes, item.getParentIdentifier(), item.getName()), ITEM_ID, NullItemData.NULL_ID); } else finally { // put in $CHILD_PROPERTIES cache.putIfAbsent(makeChildFqn(childProps, item.getParentIdentifier(), item.getName()), ITEM_ID, NullItemData.NULL_ID); } } } cache.setLocal(false); if (!inTransaction) { dedicatedTxCommit(); } } } protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption modifyListsOfChild) { // if not a root node if (node.getParentIdentifier() != null) { // add in CHILD_NODES cache.put(makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath() .getEntries().length - 1]), ITEM_ID, node.getIdentifier()); if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY) { cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node .getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); } } // add in ITEMS // NullNodeData must never be returned inside internal cache operations. ItemData returnedData = (ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node); return (returnedData instanceof NullItemData) ? null : returnedData; } /** * Internal put Property. * * @param node, PropertyData, new data to put in the cache * @return PropertyData, previous data or null */ protected PropertyData putProperty(PropertyData prop, ModifyChildOption modifyListsOfChild) { // add in CHILD_PROPS cache.put(makeChildFqn(childProps, prop.getParentIdentifier(), prop.getQPath().getEntries()[prop.getQPath() .getEntries().length - 1]), ITEM_ID, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.NOT_MODIFY); if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY) { cache.addToPatternList(makeChildListFqn(childPropsByPatternList, prop.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, prop); cache.addToList(makeChildListFqn(childPropsList, prop.getParentIdentifier()), ITEM_LIST, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); } // add referenced property if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY && prop.getType() == PropertyType.REFERENCE) { List lData = prop.getValues(); for (int i = 0, length = lData.size(); i < length; i++) { ValueData vdata = lData.get(i); String nodeIdentifier = null; try { nodeIdentifier = new String(vdata.getAsByteArray(), Constants.DEFAULT_ENCODING); } catch (IllegalStateException e) { // Do nothing. Never happens. } catch (IOException e) { // Do nothing. Never happens. } cache.addToList(makeRefFqn(nodeIdentifier), ITEM_LIST, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY); } } // add in ITEMS // NullItemData must never be returned inside internal cache operations. ItemData returnedData = (ItemData) cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop, modifyListsOfChild == ModifyChildOption.NOT_MODIFY); return (returnedData instanceof NullItemData) ? null : (PropertyData) returnedData; } protected void removeItem(ItemData item) { if (item.isNode()) { if (item.getParentIdentifier() != null) { // if not a root node // remove from CHILD_NODES of parent cache.removeNode(makeChildFqn(childNodes, item.getParentIdentifier(), item.getQPath().getEntries()[item .getQPath().getEntries().length - 1])); // remove from CHILD_NODES_LIST of parent cache.removeFromList(makeChildListFqn(childNodesList, item.getParentIdentifier()), ITEM_LIST, item .getIdentifier()); // remove from CHILD_NODES_BY_PATTERN_LIST of parent cache.removeFromPatternList(makeChildListFqn(childNodesByPatternList, item.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, item); // remove from CHILD_NODES_BY_PAGE_LIST of parent cache.removeNode(makeChildListFqn(childNodesByPageList, item.getParentIdentifier())); } // remove from CHILD_NODES as parent cache.removeNode(makeChildListFqn(childNodes, item.getIdentifier())); // remove from CHILD_NODES_LIST as parent cache.removeNode(makeChildListFqn(childNodesList, item.getIdentifier())); // remove from CHILD_PROPS as parent cache.removeNode(makeChildListFqn(childProps, item.getIdentifier())); // remove from CHILD_PROPS_LIST as parent cache.removeNode(makeChildListFqn(childPropsList, item.getIdentifier())); // remove from CHILD_NODES_BY_PAGE_LIST as parent cache.removeNode(makeChildListFqn(childNodesByPageList, item.getIdentifier())); // remove from CHILD_NODES_BY_PATTERN_LIST as parent cache.removeNode(makeChildListFqn(childNodesByPatternList, item.getIdentifier())); // remove from CHILD_PROPS_BY_PATTERN_LIST as parent cache.removeNode(makeChildListFqn(childPropsByPatternList, item.getIdentifier())); cache.removeNode(makeRefFqn(item.getIdentifier())); } else { // remove from CHILD_PROPS cache.removeNode(makeChildFqn(childProps, item.getParentIdentifier(), item.getQPath().getEntries()[item .getQPath().getEntries().length - 1])); // remove from CHILD_PROPS_LIST cache.removeFromList(makeChildListFqn(childPropsList, item.getParentIdentifier()), ITEM_LIST, item .getIdentifier()); cache.removeFromPatternList(makeChildListFqn(childPropsByPatternList, item.getParentIdentifier()), PATTERN_OBJ, ITEM_LIST, item); } // remove from ITEMS cache.removeNode(makeItemFqn(item.getIdentifier())); } /** * Update Node's mixin and ACL. * * @param node NodeData */ protected void updateMixin(NodeData node) { NodeData prevData = (NodeData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node); // prevent update NullNodeData if (prevData != null && !(prevData instanceof NullItemData)) { // do update ACL if needed if (prevData.getACL() == null || !prevData.getACL().equals(node.getACL())) { updateChildsACL(node.getIdentifier(), node.getACL()); } } else if (LOG.isDebugEnabled()) { LOG.debug("Previous NodeData not found for mixin update " + node.getQPath().getAsString()); } } /** * This method duplicate update method, except using getFromBuffer inside. * * @param node NodeData * @param prevNode NodeData */ protected void updateInBuffer(final NodeData node, final NodeData prevNode) { // I expect that NullNodeData will never update existing NodeData. // get previously cached NodeData and using its name remove child on the parent Fqn prevFqn = makeChildFqn(childNodes, node.getParentIdentifier(), prevNode.getQPath().getEntries()[prevNode.getQPath() .getEntries().length - 1]); } if (node.getIdentifier().equals(cache.getFromBuffer(prevFqn, ITEM_ID))) { // it's same-name siblings re-ordering, delete previous child if (!cache.removeNode(prevFqn) && LOG.isDebugEnabled()) { LOG.debug("Node not extists as a child but update asked " + node.getQPath().getAsString()); } } // node and prevNode are not NullNodeDatas // update childs paths if index changed int nodeIndex = node.getQPath().getEntries()[node.getQPath().getEntries().length - 1].getIndex(); int prevNodeIndex = prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1].getIndex(); if (nodeIndex != prevNodeIndex) { // its a samename reordering updateTreePath(prevNode.getQPath(), node.getQPath(), null); // don't change ACL, it's same parent } } /** * Check all items in cache - is it descendant of prevRootPath, and update path according newRootPath. * * @param prevRootPath * @param newRootPath * @param acl */ protected void updateTreePath(final QPath prevRootPath, final QPath newRootPath, final AccessControlList acl) { boolean inheritACL = acl != null; // check all ITEMS in cache Node items = cache.getNode(itemsRoot); Set childrenNames = items.getChildrenNames(); Iterator namesIt = childrenNames.iterator(); while (namesIt.hasNext()) { String id = (String)namesIt.next(); ItemData data = (ItemData)cache.get(makeItemFqn(id), ITEM_DATA); // check is this descendant of prevRootPath QPath nodeQPath = data.getQPath(); if (nodeQPath != null && nodeQPath.isDescendantOf(prevRootPath)) { //make relative path QPathEntry[] relativePath = null; try { relativePath = nodeQPath.getRelPath(nodeQPath.getDepth() - prevRootPath.getDepth()); } catch (IllegalPathException e) { // Do nothing. Never happens. } // make new path - no matter node or property QPath newPath = QPath.makeChildPath(newRootPath, relativePath); if (data.isNode()) { // update node NodeData prevNode = (NodeData)data; NodeData newNode = new PersistedNodeData(prevNode.getIdentifier(), newPath, prevNode.getParentIdentifier(), prevNode.getPersistedVersion(), prevNode.getOrderNumber(), prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), inheritACL ? acl : prevNode.getACL()); // update this node cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode); } else { //update property PropertyData prevProp = (PropertyData)data; if (inheritACL && (prevProp.getQPath().getName().equals(Constants.EXO_PERMISSIONS) || prevProp.getQPath().getName() .equals(Constants.EXO_OWNER))) { inheritACL = false; } PropertyData newProp = */ new PersistedPropertyData(prevProp.getIdentifier(), newPath, prevProp.getParentIdentifier(), prevProp.getPersistedVersion(), prevProp.getType(), prevProp.isMultiValued(), prevProp.getValues()); cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp); } } } /** * Update child Nodes ACLs. * * @param parentId String - root node id of JCR subtree. * @param acl AccessControlList */ protected void updateChildsACL(final String parentId, final AccessControlList acl) { loop: for (Iterator iter = new ChildNodesIterator(parentId); iter.hasNext();) { NodeData prevNode = iter.next(); // is ACL changes on this node (i.e. ACL inheritance broken) for (InternalQName mixin : prevNode.getMixinTypeNames()) { if (mixin.equals(Constants.EXO_PRIVILEGEABLE) || mixin.equals(Constants.EXO_OWNEABLE)) { continue loop; } } // recreate with new path for child Nodes only TransientNodeData newNode = new TransientNodeData(prevNode.getQPath(), prevNode.getIdentifier(), prevNode.getPersistedVersion(), prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode .getParentIdentifier(), acl); // update this node cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode); // update childs recursive updateChildsACL(newNode.getIdentifier(), acl); } } public void beginTransaction() { cache.beginTransaction(); } public void commitTransaction() { cache.commitTransaction(); } public void rollbackTransaction() { cache.rollbackTransaction(); } /** * {@inheritDoc} */ public boolean isTXAware() { return true; } /** *
    • NOT_MODIFY - node(property) is not added to the parent's list * (no persistent changes performed, cache used as cache)
    • *
    • MODIFY - node(property) is added to the parent's list if parent in the cache * (new item is added to persistent, add to list if it is present)
    • *
    • FORCE_MODIFY - node(property) is added to the parent's list anyway * (when list is read from DB, forcing write)
    • */ private enum ModifyChildOption { NOT_MODIFY, MODIFY, FORCE_MODIFY } /** * Allows to commit the cache changes in a dedicated XA Tx in order to avoid potential * deadlocks */ private void dedicatedTxCommit() { // Ensure that the commit is done in a dedicated tx to avoid deadlock due // to global XA Tx commitTransaction.run(); } /** * {@inheritDoc} */ public void backup(File storageDir) throws BackupException { } /** * {@inheritDoc} */ @Managed @ManagedDescription("Remove all the existing items from the cache") public void clean() throws BackupException { cleanCache(); } /** * {@inheritDoc} */ public DataRestore getDataRestorer(DataRestoreContext context) throws BackupException { return new DataRestore() { /** * {@inheritDoc} */ public void clean() throws BackupException { cleanCache(); } /** * {@inheritDoc} */ public void restore() throws BackupException { } /** * {@inheritDoc} */ public void commit() throws BackupException { } /** * {@inheritDoc} */ public void rollback() throws BackupException { } /** * {@inheritDoc} */ public void close() throws BackupException { } }; } /** * Clean all cache data. */ private void cleanCache() { if (cache.getCacheStatus() == CacheStatus.STARTED) { cache.beginTransaction(); cache.removeNode(itemsRoot); cache.removeNode(refRoot); cache.removeNode(childNodes); cache.removeNode(childProps); cache.removeNode(childNodesList); cache.removeNode(childPropsList); cache.removeNode(childNodesByPageList); cache.removeNode(childNodesByPatternList); cache.removeNode(childPropsByPatternList); cache.commitTransaction(); createResidentNode(childNodes); createResidentNode(refRoot); createResidentNode(childNodesList); createResidentNode(childProps); createResidentNode(childPropsList); createResidentNode(childNodesByPageList); createResidentNode(childNodesByPatternList); createResidentNode(childPropsByPatternList); createResidentNode(itemsRoot); } } /** * {@inheritDoc} */ public void addListener(WorkspaceStorageCacheListener listener) { // As the listeners in JBC really slow down the whole application, we decided to disable // the bloom filters in case of JBC throw new UnsupportedOperationException("The cache listeners are not supported by the JBossCacheWorkspaceStorageCache"); } /** * {@inheritDoc} */ public void removeListener(WorkspaceStorageCacheListener listener) { // As the listeners in JBC really slow down the whole application, we decided to disable // the bloom filters in case of JBC throw new UnsupportedOperationException("The cache listeners are not supported by the JBossCacheWorkspaceStorageCache"); } /** * Actions that are not supposed to be called within a transaction * * Created by The eXo Platform SAS * Author : Nicolas Filotto * nicolas.filotto@exoplatform.com * 21 janv. 2010 */ protected abstract class CacheActionNonTxAware extends ActionNonTxAware { /** * @see org.exoplatform.services.transaction.ActionNonTxAware#getTransactionManager() protected TransactionManager getTransactionManager() { return JBossCacheWorkspaceStorageCache.this.getTransactionManager(); } } }

File
JBossCacheWorkspaceStorageCache.java
Developer's decision
Version 2
Kind of conflict
Class declaration
Comment
Import
Package declaration
Chunk
Conflicting content
    * %s must be replaced with original table name before compile Pattern.
    */
   private static final String DB2_PK_CONSTRAINT_DETECT_PATTERN =
<<<<<<< HEAD
      "(.*DB2 SQL error+.*SQLCODE: -803+.*SQLSTATE: 23505+.*%s.*)+?";
   
   /**
    * MYSQL_PK_CONSTRAINT_DETECT_PATTERN.
    */
   private static final String H2_PK_CONSTRAINT_DETECT_PATTERN = 
      "(.*JdbcSQLException.*violation.*PRIMARY_KEY_.*)";
   
   /**
    * H2_PK_CONSTRAINT_DETECT.
    */
   private static final Pattern H2_PK_CONSTRAINT_DETECT = 
=======
      "(.*DB2 SQL [Ee]rror+.*SQLCODE[:=].?-803+.*SQLSTATE[:=].?23505+.*%s.*)+?";

   /**
    * MYSQL_PK_CONSTRAINT_DETECT_PATTERN.
    */
   private static final String H2_PK_CONSTRAINT_DETECT_PATTERN = "(.*JdbcSQLException.*violation.*PRIMARY_KEY_.*)";

   /**
    * H2_PK_CONSTRAINT_DETECT.
    */
   private static final Pattern H2_PK_CONSTRAINT_DETECT =
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      Pattern.compile(H2_PK_CONSTRAINT_DETECT_PATTERN, Pattern.CASE_INSENSITIVE);

   /**
Solution content
    * %s must be replaced with original table name before compile Pattern.
    */
   private static final String DB2_PK_CONSTRAINT_DETECT_PATTERN =
      "(.*DB2 SQL [Ee]rror+.*SQLCODE[:=].?-803+.*SQLSTATE[:=].?23505+.*%s.*)+?";

   /**
    * MYSQL_PK_CONSTRAINT_DETECT_PATTERN.
    */
   private static final String H2_PK_CONSTRAINT_DETECT_PATTERN = "(.*JdbcSQLException.*violation.*PRIMARY_KEY_.*)";

   /**
    * H2_PK_CONSTRAINT_DETECT.
    */
   private static final Pattern H2_PK_CONSTRAINT_DETECT =
      Pattern.compile(H2_PK_CONSTRAINT_DETECT_PATTERN, Pattern.CASE_INSENSITIVE);

   /**
File
JDBCValueContentAddressStorageImpl.java
Developer's decision
Version 2
Kind of conflict
Attribute
Comment
Chunk
Conflicting content
      {
         return DB2_PK_CONSTRAINT_DETECT.matcher(err).find();
      }
<<<<<<< HEAD
      else if (DBConstants.DB_DIALECT_H2.equalsIgnoreCase(dialect)) 
=======
      else if (DBConstants.DB_DIALECT_H2.equalsIgnoreCase(dialect))
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      {
         return H2_PK_CONSTRAINT_DETECT.matcher(err).find();
      }
Solution content
      {
         return DB2_PK_CONSTRAINT_DETECT.matcher(err).find();
      }
      else if (DBConstants.DB_DIALECT_H2.equalsIgnoreCase(dialect))
      {
         return H2_PK_CONSTRAINT_DETECT.matcher(err).find();
      }
File
JDBCValueContentAddressStorageImpl.java
Developer's decision
Version 1
Kind of conflict
If statement
Chunk
Conflicting content
         if (isAlreadyCreated)
         {
<<<<<<< HEAD
            errorTrace += next.getMessage() + "; ";
            next = next.getNextException();
=======
            LOG.warn("Could not create db schema of DataSource: '" + containerName + "'. Reason: Objects form " + sql
               + " already exists");
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
         }
         else
         {
Solution content
         if (isAlreadyCreated)
         {
            LOG.warn("Could not create db schema of DataSource: '" + containerName + "'. Reason: Objects form " + sql
               + " already exists");
         }
         else
         {
File
DBInitializer.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Variable
Chunk
Conflicting content
      {
         uuid = versionableNode.getUUID();
         path = versionableNode.getVersionHistory().getParent().getPath();
<<<<<<< HEAD
         LOG.info("Started: Import version history for node wiht path=" + path + " and UUID=" + uuid);
=======
         LOG.info("Started: Import version history for node with path=" + path + " and UUID=" + uuid);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

         NodeData versionable = (NodeData)versionableNode.getData();
         // ----- VERSIONABLE properties -----
Solution content
      {
         uuid = versionableNode.getUUID();
         path = versionableNode.getVersionHistory().getParent().getPath();
         LOG.info("Started: Import version history for node with path=" + path + " and UUID=" + uuid);

         NodeData versionable = (NodeData)versionableNode.getData();
         // ----- VERSIONABLE properties -----
File
VersionHistoryImporter.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Chunk
Conflicting content
         changesLog.add(ItemState.createAddedState(bv));
         changesLog.add(ItemState.createAddedState(pd));
         // remove version properties to avoid referential integrety check
<<<<<<< HEAD
         PlainChangesLog changesLogDeltete = new PlainChangesLogImpl();

         changesLogDeltete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:versionHistory")).getData()));
         changesLogDeltete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:baseVersion")).getData()));
         changesLogDeltete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:predecessors")).getData()));
         dataKeeper.save(changesLogDeltete);

         // remove version history
         dataKeeper.save(changesLog);
         userSession.save();
         // import new version history
         userSession.getWorkspace().importXML(path, versionHistoryStream, 0);
         userSession.save();

         LOG.info("Completed: Import version history for node wiht path=" + path + " and UUID=" + uuid);
      }
      catch (RepositoryException exception)
      {
         LOG.error("Failed: Import version history for node wiht path=" + path + " and UUID=" + uuid, exception);
         throw new RepositoryException(exception);
      }
      catch (IOException exception)
      {
         LOG.error("Failed: Import version history for node wiht path=" + path + " and UUID=" + uuid, exception);
         IOException newException = new IOException();
         newException.initCause(exception);
         throw newException;
=======
         PlainChangesLog changesLogDelete = new PlainChangesLogImpl();

         changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:versionHistory")).getData()));
         changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:baseVersion")).getData()));
         changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:predecessors")).getData()));
         dataKeeper.save(changesLogDelete);
         // remove version history
         dataKeeper.save(changesLog);
         userSession.save();

         // import new version history
         Map context = new HashMap();
         //context.put("versionablenode", versionableNode);
         context.put(ContentImporter.RESPECT_PROPERTY_DEFINITIONS_CONSTRAINTS, true);
         userSession.getWorkspace().importXML(path, versionHistoryStream, 0, context);
         userSession.save();

         LOG.info("Completed: Import version history for node with path=" + path + " and UUID=" + uuid);

         // fetch list of imported child nodes versions
         List versionUuids = (List)context.get(ContentImporter.LIST_OF_IMPORTED_VERSION_HISTORIES);
         if (versionUuids != null && !versionUuids.isEmpty())
         {
            updateVersionedChildNodes(versionUuids);
         }
      }
      catch (RepositoryException exception)
      {
         LOG.error("Failed: Import version history for node with path=" + path + " and UUID=" + uuid, exception);
         throw new RepositoryException(exception);
      }
      catch (IOException exception)
      {
         LOG.error("Failed: Import version history for node with path=" + path + " and UUID=" + uuid, exception);
         IOException newException = new IOException();
         newException.initCause(exception);
         throw newException;
      }
   }

   /**
    * Update child nodes that owns versions from versionUuids list. 
    * 
    * @param versionUuids - list of version histories uuids.
    * @throws RepositoryException
    * @throws IOException
    */
   private void updateVersionedChildNodes(List versionUuids) throws RepositoryException, IOException
   {
      SessionDataManager dataManager = userSession.getTransientNodesManager();

      NodeData versionStorage = (NodeData)dataManager.getItemData(Constants.VERSIONSTORAGE_UUID);

      for (String versionUuid : versionUuids)
      {
         NodeData versionHistoryData =
            (NodeData)dataManager.getItemData(versionStorage, new QPathEntry("", versionUuid, 1), ItemType.NODE);

         PropertyData versionableUuidProp =
            (PropertyData)dataManager.getItemData(versionHistoryData, new QPathEntry(Constants.JCR_VERSIONABLEUUID, 1),
               ItemType.PROPERTY);

         String versionableUuid = ValueDataConvertor.readString(versionableUuidProp.getValues().get(0));

         // fetch child versionable node
         NodeData versionedChild = (NodeData)dataManager.getItemData(versionableUuid);

         if (versionedChild != null && versionedChild.getQPath().isDescendantOf(versionableNode.getData().getQPath()))
         {
            // find latest version
            String latestVersionUuid = null;
            for (int versionNumber = 1;; versionNumber++)
            {
               NodeData nodeData =
                  (NodeData)dataManager.getItemData(versionHistoryData, new QPathEntry("", Integer
                     .toString(versionNumber), 1), ItemType.NODE);

               if (nodeData == null)
               {
                  break;
               }
               else
               {
                  latestVersionUuid = nodeData.getIdentifier();
               }
            }

            if (latestVersionUuid == null)
            {
               // fetch root version
               NodeData rootVersion =
                  (NodeData)dataManager.getItemData(versionHistoryData, new QPathEntry(Constants.JCR_ROOTVERSION, 1),
                     ItemType.NODE);
               latestVersionUuid = rootVersion.getIdentifier();
            }

            PropertyData propVersionHistory =
               (PropertyData)dataManager.getItemData(versionedChild, new QPathEntry(Constants.JCR_VERSIONHISTORY, 1),
                  ItemType.PROPERTY);
            String prevVerHistoryId = ValueDataConvertor.readString(propVersionHistory.getValues().get(0));

            PropertyData propBaseVersion =
               (PropertyData)dataManager.getItemData(versionedChild, new QPathEntry(Constants.JCR_BASEVERSION, 1),
                  ItemType.PROPERTY);

            PropertyData propPredecessors =
               (PropertyData)dataManager.getItemData(versionedChild, new QPathEntry(Constants.JCR_PREDECESSORS, 1),
                  ItemType.PROPERTY);

            TransientPropertyData newVersionHistoryProp =
               TransientPropertyData.createPropertyData(versionedChild, Constants.JCR_VERSIONHISTORY,
                  PropertyType.REFERENCE, false, new TransientValueData(new Identifier(versionUuid)));

            // jcr:baseVersion
            TransientPropertyData newBaseVersionProp =
               TransientPropertyData.createPropertyData(versionedChild, Constants.JCR_BASEVERSION,
                  PropertyType.REFERENCE, false, new TransientValueData(new Identifier(latestVersionUuid)));

            // jcr:predecessors
            List predecessorValues = new ArrayList();
            predecessorValues.add(new TransientValueData(new Identifier(latestVersionUuid)));
            TransientPropertyData newPredecessorsProp =
               TransientPropertyData.createPropertyData(versionedChild, Constants.JCR_PREDECESSORS,
                  PropertyType.REFERENCE, true, predecessorValues);

            //remove previous version of childnode nad update properties
            NodeData prevVersionHistory = (NodeData)dataManager.getItemData(prevVerHistoryId);

            PlainChangesLogImpl changesLog = new PlainChangesLogImpl();
            if (!prevVerHistoryId.equals(versionUuid))
            {
               RemoveVisitor rv = new RemoveVisitor();
               rv.visit(prevVersionHistory);
               changesLog.addAll(rv.getRemovedStates());
            }
            changesLog.add(ItemState.createAddedState(newVersionHistoryProp));
            changesLog.add(ItemState.createAddedState(newBaseVersionProp));
            changesLog.add(ItemState.createAddedState(newPredecessorsProp));

            PlainChangesLogImpl changesLogDelete = new PlainChangesLogImpl();
            changesLogDelete.add(ItemState.createDeletedState(propVersionHistory));
            changesLogDelete.add(ItemState.createDeletedState(propBaseVersion));
            changesLogDelete.add(ItemState.createDeletedState(propPredecessors));
            dataKeeper.save(changesLogDelete);
            // remove version history
            dataKeeper.save(changesLog);
            userSession.save();
            LOG.info("Completed: Import version history for node with path=" + versionedChild.getQPath().getAsString()
               + " and UUID=" + versionedChild.getIdentifier());
         }
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      }
   }
Solution content
   {
         changesLog.add(ItemState.createAddedState(bv));
         changesLog.add(ItemState.createAddedState(pd));
         // remove version properties to avoid referential integrety check
         PlainChangesLog changesLogDelete = new PlainChangesLogImpl();

         changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:versionHistory")).getData()));
         changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:baseVersion")).getData()));
         changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
            .getProperty("jcr:predecessors")).getData()));
         dataKeeper.save(changesLogDelete);
         // remove version history
         dataKeeper.save(changesLog);
         userSession.save();

         // import new version history
         Map context = new HashMap();
         //context.put("versionablenode", versionableNode);
         context.put(ContentImporter.RESPECT_PROPERTY_DEFINITIONS_CONSTRAINTS, true);
         userSession.getWorkspace().importXML(path, versionHistoryStream, 0, context);
         userSession.save();

         LOG.info("Completed: Import version history for node with path=" + path + " and UUID=" + uuid);

         // fetch list of imported child nodes versions
         List versionUuids = (List)context.get(ContentImporter.LIST_OF_IMPORTED_VERSION_HISTORIES);
         if (versionUuids != null && !versionUuids.isEmpty())
         {
            updateVersionedChildNodes(versionUuids);
         }
      }
      catch (RepositoryException exception)
      {
         LOG.error("Failed: Import version history for node with path=" + path + " and UUID=" + uuid, exception);
         throw new RepositoryException(exception);
      }
      catch (IOException exception)
      {
         LOG.error("Failed: Import version history for node with path=" + path + " and UUID=" + uuid, exception);
         IOException newException = new IOException();
         newException.initCause(exception);
         throw newException;
      }
   }

   /**
    * Update child nodes that owns versions from versionUuids list. 
    * 
    * @param versionUuids - list of version histories uuids.
    * @throws RepositoryException
    * @throws IOException
    */
   private void updateVersionedChildNodes(List versionUuids) throws RepositoryException, IOException
      SessionDataManager dataManager = userSession.getTransientNodesManager();

      NodeData versionStorage = (NodeData)dataManager.getItemData(Constants.VERSIONSTORAGE_UUID);

      for (String versionUuid : versionUuids)
      {
         NodeData versionHistoryData =
            (NodeData)dataManager.getItemData(versionStorage, new QPathEntry("", versionUuid, 1), ItemType.NODE);

         PropertyData versionableUuidProp =
            (PropertyData)dataManager.getItemData(versionHistoryData, new QPathEntry(Constants.JCR_VERSIONABLEUUID, 1),
               ItemType.PROPERTY);

         String versionableUuid = ValueDataConvertor.readString(versionableUuidProp.getValues().get(0));

         // fetch child versionable node

         NodeData versionedChild = (NodeData)dataManager.getItemData(versionableUuid);

         if (versionedChild != null && versionedChild.getQPath().isDescendantOf(versionableNode.getData().getQPath()))
         {
            // find latest version
            String latestVersionUuid = null;
            for (int versionNumber = 1;; versionNumber++)
            {
               NodeData nodeData =
                  (NodeData)dataManager.getItemData(versionHistoryData, new QPathEntry("", Integer
                     .toString(versionNumber), 1), ItemType.NODE);

               if (nodeData == null)
               {
                  break;
               }
               else
               {
                  latestVersionUuid = nodeData.getIdentifier();
               }
            }

            if (latestVersionUuid == null)
            {
               // fetch root version
               NodeData rootVersion =
                  (NodeData)dataManager.getItemData(versionHistoryData, new QPathEntry(Constants.JCR_ROOTVERSION, 1),
                     ItemType.NODE);
               latestVersionUuid = rootVersion.getIdentifier();
            }

            PropertyData propVersionHistory =
               (PropertyData)dataManager.getItemData(versionedChild, new QPathEntry(Constants.JCR_VERSIONHISTORY, 1),
                  ItemType.PROPERTY);
            String prevVerHistoryId = ValueDataConvertor.readString(propVersionHistory.getValues().get(0));

            PropertyData propBaseVersion =
               (PropertyData)dataManager.getItemData(versionedChild, new QPathEntry(Constants.JCR_BASEVERSION, 1),
                  ItemType.PROPERTY);

            PropertyData propPredecessors =
               (PropertyData)dataManager.getItemData(versionedChild, new QPathEntry(Constants.JCR_PREDECESSORS, 1),
                  ItemType.PROPERTY);

            TransientPropertyData newVersionHistoryProp =
               TransientPropertyData.createPropertyData(versionedChild, Constants.JCR_VERSIONHISTORY,
                  PropertyType.REFERENCE, false, new TransientValueData(new Identifier(versionUuid)));

            // jcr:baseVersion
            TransientPropertyData newBaseVersionProp =
               TransientPropertyData.createPropertyData(versionedChild, Constants.JCR_BASEVERSION,
                  PropertyType.REFERENCE, false, new TransientValueData(new Identifier(latestVersionUuid)));

            // jcr:predecessors
            List predecessorValues = new ArrayList();
            predecessorValues.add(new TransientValueData(new Identifier(latestVersionUuid)));
            TransientPropertyData newPredecessorsProp =
               TransientPropertyData.createPropertyData(versionedChild, Constants.JCR_PREDECESSORS,
                  PropertyType.REFERENCE, true, predecessorValues);

            //remove previous version of childnode nad update properties
            NodeData prevVersionHistory = (NodeData)dataManager.getItemData(prevVerHistoryId);

            PlainChangesLogImpl changesLog = new PlainChangesLogImpl();
            if (!prevVerHistoryId.equals(versionUuid))
            {
               RemoveVisitor rv = new RemoveVisitor();
               rv.visit(prevVersionHistory);
               changesLog.addAll(rv.getRemovedStates());
            }
            changesLog.add(ItemState.createAddedState(newVersionHistoryProp));
            changesLog.add(ItemState.createAddedState(newBaseVersionProp));
            changesLog.add(ItemState.createAddedState(newPredecessorsProp));

            PlainChangesLogImpl changesLogDelete = new PlainChangesLogImpl();
            changesLogDelete.add(ItemState.createDeletedState(propVersionHistory));
            changesLogDelete.add(ItemState.createDeletedState(propBaseVersion));
            changesLogDelete.add(ItemState.createDeletedState(propPredecessors));
            dataKeeper.save(changesLogDelete);
            // remove version history
            dataKeeper.save(changesLog);
            userSession.save();
            LOG.info("Completed: Import version history for node with path=" + versionedChild.getQPath().getAsString()
               + " and UUID=" + versionedChild.getIdentifier());
         }
      }
   }
File
VersionHistoryImporter.java
Developer's decision
Version 2
Kind of conflict
Cast expression
Catch clause
Comment
For statement
If statement
Method invocation
Method signature
Throw statement
Variable
Chunk
Conflicting content
    */
   public void restore() throws IOException
   {
<<<<<<< HEAD
      // TODO same code as in BackupWorkspaceInitializer?

=======
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      List listItemState = itemDataChangesLog.getAllStates();
      for (int i = 0; i < this.listFixupStream.size(); i++)
      {
Solution content
    */
   public void restore() throws IOException
   {
      List listItemState = itemDataChangesLog.getAllStates();
      for (int i = 0; i < this.listFixupStream.size(); i++)
      {
File
PendingChangesLog.java
Developer's decision
Version 2
Kind of conflict
Comment
Chunk
Conflicting content
         ValueData vd = (propertyData.getValues().get(listFixupStream.get(i).getValueDataId()));

         // re-init the value
<<<<<<< HEAD
         tvd.delegate(new TransientValueData(tvd.getOrderNumber(), null, null, new SpoolFile(listFile.get(i)
            .getAbsolutePath()), fileCleaner, -1, null, true));
=======
         propertyData.getValues().set(listFixupStream.get(i).getValueDataId(),
            new StreamPersistedValueData(vd.getOrderNumber(), listFile.get(i)));
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
      }

      if (listRandomAccessFile != null)
Solution content
         ValueData vd = (propertyData.getValues().get(listFixupStream.get(i).getValueDataId()));

         // re-init the value
         propertyData.getValues().set(listFixupStream.get(i).getValueDataId(),
            new StreamPersistedValueData(vd.getOrderNumber(), listFile.get(i)));
      }

      if (listRandomAccessFile != null)
File
PendingChangesLog.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Chunk
Conflicting content
            if (replaceForbiddenChars)
            {
<<<<<<< HEAD
              curPathName = FtpTextUtils.replaceForbiddenChars(curPathName, ftpConfig.getForbiddenChars(), ftpConfig.getReplaceChar());
=======
               curPathName =
                        FtpTextUtils.replaceForbiddenChars(curPathName, ftpConfig.getForbiddenChars(), ftpConfig
                                 .getReplaceChar());
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
            }

            if (parentNode.hasNode(curPathName))
Solution content
            if (replaceForbiddenChars)
            {
               curPathName =
                        FtpTextUtils.replaceForbiddenChars(curPathName, ftpConfig.getForbiddenChars(), ftpConfig
                                 .getReplaceChar());
            }

            if (parentNode.hasNode(curPathName))
File
CmdMkd.java
Developer's decision
Version 1
Kind of conflict
Method invocation
Variable
Chunk
Conflicting content
         if (ftpConfig.isReplaceForbiddenChars())
         {
            String fName = newPath.get(newPath.size()-1);
<<<<<<< HEAD
            String newfName = FtpTextUtils.replaceForbiddenChars(fName, ftpConfig.getForbiddenChars(), ftpConfig.getReplaceChar());
=======
            String newfName =
                     FtpTextUtils.replaceForbiddenChars(fName, ftpConfig.getForbiddenChars(), ftpConfig
                              .getReplaceChar());
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
            
            fileName  = fileName.substring(0, fileName.indexOf(fName)) + newfName;
         }
Solution content
         if (ftpConfig.isReplaceForbiddenChars())
         {
            String fName = newPath.get(newPath.size()-1);
            String newfName =
                     FtpTextUtils.replaceForbiddenChars(fName, ftpConfig.getForbiddenChars(), ftpConfig
                              .getReplaceChar());
            
            fileName  = fileName.substring(0, fileName.indexOf(fName)) + newfName;
         }
File
CmdStor.java
Developer's decision
Version 1
Kind of conflict
Method invocation
Variable
Chunk
Conflicting content
    * @return the instance of javax.ws.rs.core.Response
    */
   Response put(String repoName, String repoPath, String lockTokenHeader, String ifHeader, String fileNodeTypeHeader,
<<<<<<< HEAD
      String contentNodeTypeHeader, String mixinTypes, MediaType mediatype, InputStream inputStream);
=======
      String contentNodeTypeHeader, String mixinTypes, MediaType mediatype, String userAgent, InputStream inputStream,
      UriInfo uriInfo);
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

   /**
    * @param repoName repository name
Solution content
    * @return the instance of javax.ws.rs.core.Response
    */
   Response put(String repoName, String repoPath, String lockTokenHeader, String ifHeader, String fileNodeTypeHeader,
      String contentNodeTypeHeader, String mixinTypes, MediaType mediatype, String userAgent, InputStream inputStream,
      UriInfo uriInfo);

   /**
    * @param repoName repository name
File
WebDavService.java
Developer's decision
Version 2
Kind of conflict
Variable
Chunk
Conflicting content
   public Response mkcol(@PathParam("repoName") String repoName, @PathParam("repoPath") String repoPath,
      @HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader, @HeaderParam(ExtHttpHeaders.IF) String ifHeader,
      @HeaderParam(ExtHttpHeaders.CONTENT_NODETYPE) String nodeTypeHeader,
<<<<<<< HEAD
      @HeaderParam(ExtHttpHeaders.CONTENT_MIXINTYPES) String mixinTypesHeader)
=======
      @HeaderParam(ExtHttpHeaders.CONTENT_MIXINTYPES) String mixinTypesHeader, @Context UriInfo uriInfo)
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   {

      if (log.isDebugEnabled())
Solution content
   public Response mkcol(@PathParam("repoName") String repoName, @PathParam("repoPath") String repoPath,
      @HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader, @HeaderParam(ExtHttpHeaders.IF) String ifHeader,
      @HeaderParam(ExtHttpHeaders.CONTENT_NODETYPE) String nodeTypeHeader,
      @HeaderParam(ExtHttpHeaders.CONTENT_MIXINTYPES) String mixinTypesHeader, @Context UriInfo uriInfo)
   {

      if (log.isDebugEnabled())
File
WebDavServiceImpl.java
Developer's decision
Version 2
Kind of conflict
Variable
Chunk
Conflicting content
      @HeaderParam(ExtHttpHeaders.FILE_NODETYPE) String fileNodeTypeHeader,
      @HeaderParam(ExtHttpHeaders.CONTENT_NODETYPE) String contentNodeTypeHeader,
      @HeaderParam(ExtHttpHeaders.CONTENT_MIXINTYPES) String mixinTypes,
<<<<<<< HEAD
      @HeaderParam(ExtHttpHeaders.CONTENT_TYPE) MediaType mediatype, InputStream inputStream)
=======
      @HeaderParam(ExtHttpHeaders.CONTENT_TYPE) MediaType mediatype,
      @HeaderParam(ExtHttpHeaders.USER_AGENT) String userAgent, InputStream inputStream, @Context UriInfo uriInfo)
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7
   {
      if (log.isDebugEnabled())
      {
Solution content
      {
      @HeaderParam(ExtHttpHeaders.FILE_NODETYPE) String fileNodeTypeHeader,
      @HeaderParam(ExtHttpHeaders.CONTENT_NODETYPE) String contentNodeTypeHeader,
      @HeaderParam(ExtHttpHeaders.CONTENT_MIXINTYPES) String mixinTypes,
      @HeaderParam(ExtHttpHeaders.CONTENT_TYPE) MediaType mediatype,
      @HeaderParam(ExtHttpHeaders.USER_AGENT) String userAgent, InputStream inputStream, @Context UriInfo uriInfo)
   {
      if (log.isDebugEnabled())
File
WebDavServiceImpl.java
Developer's decision
Version 2
Kind of conflict
Variable
Chunk
Conflicting content
               xmlStreamWriter.writeStartElement("DAV:", "response");

<<<<<<< HEAD
            xmlStreamWriter.writeStartElement("DAV:", "href");
            xmlStreamWriter.writeCharacters(URLDecoder.decode(resource.getIdentifier().toASCIIString(), "UTF-8"));
            xmlStreamWriter.writeEndElement();
=======
               xmlStreamWriter.writeStartElement("DAV:", "href");
               xmlStreamWriter.writeCharacters(resource.getIdentifier().toASCIIString());
               xmlStreamWriter.writeEndElement();
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

               PropstatGroupedRepresentation propstat = new PropstatGroupedRepresentation(resource, properties, false);
Solution content

               xmlStreamWriter.writeStartElement("DAV:", "response");

               xmlStreamWriter.writeStartElement("DAV:", "href");
               xmlStreamWriter.writeCharacters(resource.getIdentifier().toASCIIString());
               xmlStreamWriter.writeEndElement();
               PropstatGroupedRepresentation propstat = new PropstatGroupedRepresentation(resource, properties, false);
File
SearchResultResponseEntity.java
Developer's decision
Version 2
Kind of conflict
Method invocation
Chunk
Conflicting content
import java.util.ArrayList;
import java.util.Arrays;
<<<<<<< HEAD
import java.util.List;
=======
>>>>>>> 9ce46692944ade01262c4e66f838f4ab4a48bea7

import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
Solution content
import java.util.ArrayList;
import java.util.Arrays;

import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
File
NodeTypeUtil.java
Developer's decision
Version 2
Kind of conflict
Import