exo-jcr SVN: r3984 - in jcr/branches/1.12.x/patch/1.12.8-GA: JCR-1584 and 1 other directory.
by do-not-reply@jboss.org
Author: sergiykarpenko
Date: 2011-02-17 11:17:58 -0500 (Thu, 17 Feb 2011)
New Revision: 3984
Added:
jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1584/
jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1584/JCR-1584.patch
Log:
JCR-1584: patch proposed
Added: jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1584/JCR-1584.patch
===================================================================
--- jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1584/JCR-1584.patch (rev 0)
+++ jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1584/JCR-1584.patch 2011-02-17 16:17:58 UTC (rev 3984)
@@ -0,0 +1,1386 @@
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/Constants.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/Constants.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/Constants.java (working copy)
+@@ -569,6 +569,11 @@
+ public static final String SV_NODE = "node";
+
+ /**
++ * SV_VERSION_HISTORY.
++ */
++ public static final String SV_VERSION_HISTORY = "versionhistory";
++
++ /**
+ * SV_PROPERTY.
+ */
+ public static final String SV_PROPERTY = "property";
+@@ -604,6 +609,11 @@
+ public static final InternalQName SV_NODE_NAME = new InternalQName(NS_SV_URI, SV_NODE);
+
+ /**
++ * sv:versionhistory internal name.
++ */
++ public static final InternalQName SV_VERSION_HISTORY_NAME = new InternalQName(NS_SV_URI, SV_VERSION_HISTORY);
++
++ /**
+ * sv:property internal name.
+ */
+ public static final InternalQName SV_PROPERTY_NAME = new InternalQName(NS_SV_URI, SV_PROPERTY);
+@@ -667,7 +677,7 @@
+ * eXo JCR default Strings encoding.
+ */
+ public static final String DEFAULT_ENCODING = "UTF-8";
+-
++
+ /**
+ * System identifier for remote workspace initializer changes.
+ */
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionImpl.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionImpl.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionImpl.java (working copy)
+@@ -403,11 +403,15 @@
+ ValueFactoryImpl valueFactoryImpl = new ValueFactoryImpl(factory, wsConfig, cleanerHolder);
+ try
+ {
++ JCRPath srcNodePath = getLocationFactory().parseAbsPath(absPath);
++
++ boolean isVersionHistoryExport =
++ srcNodePath.getInternalPath().isDescendantOf(Constants.JCR_VERSION_STORAGE_PATH);
++
+ BaseXmlExporter exporter =
+ new ExportImportFactory().getExportVisitor(XmlMapping.SYSVIEW, out, skipBinary, noRecurse,
+- getTransientNodesManager(), repository.getNamespaceRegistry(), valueFactoryImpl);
++ isVersionHistoryExport, getTransientNodesManager(), repository.getNamespaceRegistry(), valueFactoryImpl);
+
+- JCRPath srcNodePath = getLocationFactory().parseAbsPath(absPath);
+ ItemData srcItemData = dataManager.getItemData(srcNodePath.getInternalPath());
+
+ if (srcItemData == null)
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/ExportImportFactory.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/ExportImportFactory.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/ExportImportFactory.java (working copy)
+@@ -112,7 +112,33 @@
+ ItemDataConsumer dataManager, NamespaceRegistry namespaceRegistry, ValueFactoryImpl systemValueFactory)
+ throws NamespaceException, RepositoryException, IOException
+ {
++ return getExportVisitor(type, stream, skipBinary, noRecurse, false, dataManager, namespaceRegistry,
++ systemValueFactory);
++ }
+
++ /**
++ * Create export visitor for given type of view.\
++ *
++ * @param type - 6.4 XML Mappings
++ * @param stream - output result stream
++ * @param skipBinary- If skipBinary is true then any properties of
++ * PropertyType.BINARY will be serialized as if they are empty.
++ * @param noRecurse- if noRecurse is false, the whole subtree are serialized
++ * @param exportChildVersionHistory - does versioned child nodes version history must be exported
++ * (works ONLY with system view).
++ * @param dataManager - ItemDataConsumer
++ * @param namespaceRegistry - NamespaceRegistry
++ * @param systemValueFactory - default value factory
++ * @return - visitor BaseXmlExporter.
++ * @throws NamespaceException
++ * @throws RepositoryException
++ * @throws IOException
++ */
++ public BaseXmlExporter getExportVisitor(XmlMapping type, OutputStream stream, boolean skipBinary, boolean noRecurse,
++ boolean exportChildVersionHistory, ItemDataConsumer dataManager, NamespaceRegistry namespaceRegistry,
++ ValueFactoryImpl systemValueFactory) throws NamespaceException, RepositoryException, IOException
++ {
++
+ XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
+ XMLStreamWriter streamWriter;
+ try
+@@ -127,7 +153,7 @@
+ if (type == XmlMapping.SYSVIEW)
+ {
+ return new SystemViewStreamExporter(streamWriter, dataManager, namespaceRegistry, systemValueFactory,
+- skipBinary, noRecurse);
++ skipBinary, noRecurse, exportChildVersionHistory);
+ }
+ else if (type == XmlMapping.DOCVIEW)
+ {
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/DocumentViewStreamExporter.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/DocumentViewStreamExporter.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/DocumentViewStreamExporter.java (working copy)
+@@ -49,7 +49,7 @@
+ NamespaceRegistry namespaceRegistry, ValueFactoryImpl systemValueFactory, boolean skipBinary, boolean noRecurse)
+ throws NamespaceException, RepositoryException
+ {
+- super(writer, dataManager, namespaceRegistry, systemValueFactory, skipBinary, noRecurse);
++ super(writer, dataManager, namespaceRegistry, systemValueFactory, skipBinary, noRecurse, false);
+ }
+
+ /**
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/StreamExporter.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/StreamExporter.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/StreamExporter.java (working copy)
+@@ -38,14 +38,22 @@
+
+ protected final XMLStreamWriter writer;
+
++ protected final boolean exportChildVersionHistory;
++
+ public StreamExporter(XMLStreamWriter writer, ItemDataConsumer dataManager, NamespaceRegistry namespaceRegistry,
+ ValueFactoryImpl systemValueFactory, boolean skipBinary, boolean noRecurse) throws NamespaceException,
+ RepositoryException
+ {
++ this(writer, dataManager, namespaceRegistry, systemValueFactory, skipBinary, noRecurse, false);
++ }
+
++ public StreamExporter(XMLStreamWriter writer, ItemDataConsumer dataManager, NamespaceRegistry namespaceRegistry,
++ ValueFactoryImpl systemValueFactory, boolean skipBinary, boolean noRecurse, boolean exportChildVersionHistory)
++ throws NamespaceException, RepositoryException
++ {
+ super(dataManager, namespaceRegistry, systemValueFactory, skipBinary, noRecurse, noRecurse ? 1 : -1);
+ this.writer = writer;
+-
++ this.exportChildVersionHistory = exportChildVersionHistory;
+ }
+
+ @Override
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/SystemViewStreamExporter.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/SystemViewStreamExporter.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/exporting/SystemViewStreamExporter.java (working copy)
+@@ -21,14 +21,17 @@
+ import org.apache.ws.commons.util.Base64;
+ import org.exoplatform.services.jcr.core.ExtendedPropertyType;
+ import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
++import org.exoplatform.services.jcr.datamodel.ItemType;
+ import org.exoplatform.services.jcr.datamodel.NodeData;
+ import org.exoplatform.services.jcr.datamodel.PropertyData;
++import org.exoplatform.services.jcr.datamodel.QPathEntry;
+ import org.exoplatform.services.jcr.datamodel.ValueData;
+ import org.exoplatform.services.jcr.impl.Constants;
+ import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
+
+ import java.io.IOException;
+ import java.io.InputStream;
++import java.util.ArrayList;
+ import java.util.List;
+
+ import javax.jcr.NamespaceException;
+@@ -47,6 +50,8 @@
+
+ private static final int BUFFER_SIZE = 3 * 1024 * 3;
+
++ private static final List<String> exportedVersionHistories = new ArrayList<String>();
++
+ /**
+ * @param writer
+ * @param session
+@@ -59,9 +64,17 @@
+ NamespaceRegistry namespaceRegistry, ValueFactoryImpl systemValueFactory, boolean skipBinary, boolean noRecurse)
+ throws NamespaceException, RepositoryException
+ {
+- super(writer, dataManager, namespaceRegistry, systemValueFactory, skipBinary, noRecurse);
++ this(writer, dataManager, namespaceRegistry, systemValueFactory, skipBinary, noRecurse, false);
+ }
+
++ public SystemViewStreamExporter(XMLStreamWriter writer, ItemDataConsumer dataManager,
++ NamespaceRegistry namespaceRegistry, ValueFactoryImpl systemValueFactory, boolean skipBinary, boolean noRecurse,
++ boolean exportChildVersionHistory) throws NamespaceException, RepositoryException
++ {
++ super(writer, dataManager, namespaceRegistry, systemValueFactory, skipBinary, noRecurse,
++ exportChildVersionHistory);
++ }
++
+ /*
+ * (non-Javadoc)
+ * @see
+@@ -145,6 +158,40 @@
+ {
+ try
+ {
++ if (exportChildVersionHistory && node.getPrimaryTypeName().equals(Constants.NT_VERSIONEDCHILD))
++ {
++ try
++ {
++ PropertyData childVersionHistory =
++ ((PropertyData)dataManager.getItemData(node, new QPathEntry(Constants.JCR_CHILDVERSIONHISTORY, 1),
++ ItemType.PROPERTY));
++ String childVersionHistoryId =
++ getValueAsStringForExport(childVersionHistory.getValues().get(0), childVersionHistory.getType());
++
++ //check does this child version history was already exported
++ if (!exportedVersionHistories.contains(childVersionHistoryId))
++ {
++
++ writer.writeStartElement(Constants.NS_SV_PREFIX, Constants.SV_VERSION_HISTORY, getSvNamespaceUri());
++ writer.writeAttribute(Constants.NS_SV_PREFIX, getSvNamespaceUri(), Constants.SV_NAME,
++ childVersionHistoryId);
++
++ NodeData versionStorage = (NodeData)dataManager.getItemData(Constants.VERSIONSTORAGE_UUID);
++ NodeData childVersionNodeData =
++ (NodeData)dataManager.getItemData(versionStorage, new QPathEntry("", childVersionHistoryId, 1),
++ ItemType.NODE);
++ childVersionNodeData.accept(this);
++
++ writer.writeEndElement();
++ exportedVersionHistories.add(childVersionHistoryId);
++ }
++ }
++ catch (IOException e)
++ {
++ throw new RepositoryException("Can't export versioned child version history: " + e.getMessage(), e);
++ }
++ }
++
+ writer.writeEndElement();
+ }
+ catch (XMLStreamException e)
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/BaseXmlImporter.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/BaseXmlImporter.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/BaseXmlImporter.java (working copy)
+@@ -383,7 +383,7 @@
+ */
+ protected void checkReferenceable(ImportNodeData currentNodeInfo, String olUuid) throws RepositoryException
+ {
+- // if node is in version storrage - do not assign new id from jcr:uuid
++ // if node is in version storage - do not assign new id from jcr:uuid
+ // property
+ if (Constants.JCR_VERSION_STORAGE_PATH.getDepth() + 3 <= currentNodeInfo.getQPath().getDepth()
+ && currentNodeInfo.getQPath().getEntries()[Constants.JCR_VERSION_STORAGE_PATH.getDepth() + 3]
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/ContentImporter.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/ContentImporter.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/ContentImporter.java (working copy)
+@@ -35,6 +35,8 @@
+ */
+ public String RESPECT_PROPERTY_DEFINITIONS_CONSTRAINTS = "respectPropertyDefinitionsConstraints";
+
++ public final String LIST_OF_IMPORTED_VERSION_HISTORIES = "importedSubversions";
++
+ /**
+ * Receive notification of character data.
+ *
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java (working copy)
+@@ -27,8 +27,10 @@
+ import org.exoplatform.services.jcr.datamodel.IllegalNameException;
+ import org.exoplatform.services.jcr.datamodel.IllegalPathException;
+ import org.exoplatform.services.jcr.datamodel.InternalQName;
++import org.exoplatform.services.jcr.datamodel.ItemType;
+ import org.exoplatform.services.jcr.datamodel.NodeData;
+ 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.core.JCRName;
+@@ -36,6 +38,7 @@
+ import org.exoplatform.services.jcr.impl.core.RepositoryImpl;
+ import org.exoplatform.services.jcr.impl.core.value.BaseValue;
+ import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
++import org.exoplatform.services.jcr.impl.dataflow.ItemDataRemoveVisitor;
+ import org.exoplatform.services.jcr.impl.dataflow.TransientValueData;
+ import org.exoplatform.services.jcr.impl.dataflow.ValueDataConvertor;
+ import org.exoplatform.services.jcr.impl.xml.DecodedValue;
+@@ -171,6 +174,11 @@
+ DecodedValue curPropValue = propertyInfo.getValues().get(propertyInfo.getValues().size() - 1);
+ curPropValue.setComplete(true);
+ }
++ else if (Constants.SV_VERSION_HISTORY_NAME.equals(elementName))
++ {
++ // remove version history node from tree
++ tree.pop();
++ }
+ else
+ {
+ throw new RepositoryException("invalid element in system view xml document: " + localName);
+@@ -260,6 +268,27 @@
+ propertyInfo.getValues().add(new DecodedValue());
+
+ }
++ else if (Constants.SV_VERSION_HISTORY_NAME.equals(elementName))
++ {
++ String svName = getAttribute(atts, Constants.SV_NAME_NAME);
++ if (svName == null)
++ {
++ throw new RepositoryException("Missing mandatory sv:name attribute of element sv:node");
++ }
++
++ NodeData versionStorage = (NodeData)this.dataConsumer.getItemData(Constants.VERSIONSTORAGE_UUID);
++
++ NodeData versionHistory =
++ (NodeData)dataConsumer.getItemData(versionStorage, new QPathEntry("", svName, 1), ItemType.NODE);
++
++ if (versionHistory != null)
++ {
++ RemoveVisitor rv = new RemoveVisitor();
++ rv.visit(versionHistory);
++ changesLog.addAll(rv.getRemovedStates());
++ }
++ tree.push(versionStorage);
++ }
+ else
+ {
+ throw new RepositoryException("Unknown element " + elementName.getAsString());
+@@ -306,9 +335,27 @@
+ private void endNode() throws RepositoryException
+ {
+ ImportNodeData currentNodeInfo = (ImportNodeData)tree.pop();
++ NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getIdentifier());
+
+- NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getIdentifier());
+-
++ //check is it child nodes version history
++
++ if (!tree.isEmpty())
++ {
++ NodeData parentNodeData = tree.pop();
++ if (!tree.isEmpty() && parentNodeData.getIdentifier().equals(Constants.VERSIONSTORAGE_UUID)
++ && tree.peek().getPrimaryTypeName().equals(Constants.NT_VERSIONEDCHILD))
++ {
++ List<String> list = (List<String>)context.get(ContentImporter.LIST_OF_IMPORTED_VERSION_HISTORIES);
++ if (list == null)
++ {
++ list = new ArrayList<String>();
++ }
++ list.add(currentNodeInfo.getQName().getName());
++ context.put(ContentImporter.LIST_OF_IMPORTED_VERSION_HISTORIES, list);
++ }
++ tree.push(parentNodeData);
++ }
++
+ if (currentNodePropertiesInfo != null)
+ {
+ checkProperties(currentNodePropertiesInfo);
+@@ -418,9 +465,16 @@
+ {
+ NodeData parentNodeData = getParent();
+ // nodeTypeDataManager.findChildNodeDefinition(primaryTypeName,)
+- if (!nodeTypeDataManager.isChildNodePrimaryTypeAllowed(primaryTypeName, parentNodeData.getPrimaryTypeName(),
+- parentNodeData.getMixinTypeNames()))
++
++ // check is node data descendant of frozenNode and primary type is nt:versionedChild
++ if (nodeData.getQPath().getDepth() > 6 && nodeData.getQPath().getEntries()[5].equals(Constants.JCR_FROZENNODE)
++ && primaryTypeName.equals(Constants.NT_VERSIONEDCHILD))
+ {
++ //do nothing
++ }
++ else if (!nodeTypeDataManager.isChildNodePrimaryTypeAllowed(primaryTypeName, parentNodeData
++ .getPrimaryTypeName(), parentNodeData.getMixinTypeNames()))
++ {
+ throw new ConstraintViolationException("Can't add node " + nodeData.getQName().getAsString() + " to "
+ + parentNodeData.getQPath().getAsString() + " node type " + sName
+ + " is not allowed as child's node type for parent node type "
+@@ -555,7 +609,7 @@
+ propertyData =
+ new ImportPropertyData(QPath.makeChildPath(currentNodeInfo.getQPath(), propertyInfo.getName()), propertyInfo
+ .getIndentifer(), 0, propertyInfo.getType(), currentNodeInfo.getIdentifier(), false);
+-
++
+ if (currentNodeInfo.getQPath().isDescendantOf(Constants.JCR_VERSION_STORAGE_PATH))
+ {
+ propertyData.setValue(new TransientValueData(propertyInfo.getValues().get(0).toString()));
+@@ -676,4 +730,26 @@
+ JCRName jname = locationFactory.createJCRName(name);
+ return attributes.get(jname.getAsString());
+ }
++
++ protected class RemoveVisitor extends ItemDataRemoveVisitor
++ {
++ /**
++ * Default constructor.
++ *
++ * @throws RepositoryException - exception.
++ */
++ RemoveVisitor() throws RepositoryException
++ {
++ super(dataConsumer, null, nodeTypeDataManager, accessManager, userState);
++ }
++
++ /**
++ * {@inheritDoc}
++ */
++ protected void validateReferential(NodeData node) throws RepositoryException
++ {
++ // no REFERENCE validation here
++ }
++ };
++
+ }
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/util/VersionHistoryImporter.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/util/VersionHistoryImporter.java (revision 3980)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/util/VersionHistoryImporter.java (working copy)
+@@ -23,23 +23,31 @@
+ import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
+ import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
+ import org.exoplatform.services.jcr.datamodel.Identifier;
++import org.exoplatform.services.jcr.datamodel.ItemType;
+ import org.exoplatform.services.jcr.datamodel.NodeData;
++import org.exoplatform.services.jcr.datamodel.PropertyData;
++import org.exoplatform.services.jcr.datamodel.QPathEntry;
+ import org.exoplatform.services.jcr.datamodel.ValueData;
+ import org.exoplatform.services.jcr.impl.Constants;
+ import org.exoplatform.services.jcr.impl.core.NodeImpl;
+ import org.exoplatform.services.jcr.impl.core.PropertyImpl;
++import org.exoplatform.services.jcr.impl.core.SessionDataManager;
+ import org.exoplatform.services.jcr.impl.core.SessionImpl;
+ import org.exoplatform.services.jcr.impl.dataflow.ItemDataRemoveVisitor;
+ import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
+ import org.exoplatform.services.jcr.impl.dataflow.TransientValueData;
++import org.exoplatform.services.jcr.impl.dataflow.ValueDataConvertor;
+ import org.exoplatform.services.jcr.impl.xml.ItemDataKeeperAdapter;
++import org.exoplatform.services.jcr.impl.xml.importing.ContentImporter;
+ import org.exoplatform.services.log.ExoLogger;
+ import org.exoplatform.services.log.Log;
+
+ import java.io.IOException;
+ import java.io.InputStream;
+ import java.util.ArrayList;
++import java.util.HashMap;
+ import java.util.List;
++import java.util.Map;
+
+ import javax.jcr.PropertyType;
+ import javax.jcr.RepositoryException;
+@@ -176,23 +184,34 @@
+ changesLog.add(ItemState.createAddedState(bv));
+ changesLog.add(ItemState.createAddedState(pd));
+ // remove version properties to avoid referential integrety check
+- PlainChangesLog changesLogDeltete = new PlainChangesLogImpl();
++ PlainChangesLog changesLogDelete = new PlainChangesLogImpl();
+
+- changesLogDeltete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
++ changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
+ .getProperty("jcr:versionHistory")).getData()));
+- changesLogDeltete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
++ changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
+ .getProperty("jcr:baseVersion")).getData()));
+- changesLogDeltete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
++ changesLogDelete.add(ItemState.createDeletedState(((PropertyImpl)versionableNode
+ .getProperty("jcr:predecessors")).getData()));
+- dataKeeper.save(changesLogDeltete);
++ dataKeeper.save(changesLogDelete);
+ // remove version history
+ dataKeeper.save(changesLog);
+ userSession.save();
++
+ // import new version history
+- userSession.getWorkspace().importXML(path, versionHistoryStream, 0);
++ Map<String, Object> context = new HashMap<String, Object>();
++ //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 wiht path=" + path + " and UUID=" + uuid);
++
++ // fetch list of imported child nodes versions
++ List<String> versionUuids = (List<String>)context.get(ContentImporter.LIST_OF_IMPORTED_VERSION_HISTORIES);
++ if (versionUuids != null && !versionUuids.isEmpty())
++ {
++ updateVersionedChildNodes(versionUuids);
++ }
+ }
+ catch (RepositoryException exception)
+ {
+@@ -209,6 +228,120 @@
+ }
+
+ /**
++ * Update child nodes that owns versions from versionUuids list.
++ *
++ * @param versionUuids - list of version histories uuids.
++ * @throws RepositoryException
++ * @throws IOException
++ */
++ private void updateVersionedChildNodes(List<String> 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<ValueData> predecessorValues = new ArrayList<ValueData>();
++ 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 wiht path=" + versionedChild.getQPath().getAsString()
++ + " and UUID=" + versionedChild.getIdentifier());
++ }
++ }
++ }
++
++ /**
+ * Remover helper.
+ *
+ * @author sj
+Index: exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/importing/TestImportVersionedChild.java
+===================================================================
+--- exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/importing/TestImportVersionedChild.java (revision 0)
++++ exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/importing/TestImportVersionedChild.java (revision 0)
+@@ -0,0 +1,770 @@
++/*
++ * Copyright (C) 2003-2011 eXo Platform SAS.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Affero General Public License
++ * as published by the Free Software Foundation; either version 3
++ * of the License, or (at your option) any later version.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see<http://www.gnu.org/licenses/>.
++ */
++package org.exoplatform.services.jcr.api.importing;
++
++import org.exoplatform.commons.utils.MimeTypeResolver;
++import org.exoplatform.services.jcr.JcrAPIBaseTest;
++import org.exoplatform.services.jcr.impl.core.NodeImpl;
++import org.exoplatform.services.jcr.impl.core.SessionImpl;
++import org.exoplatform.services.jcr.util.VersionHistoryImporter;
++
++import java.io.ByteArrayInputStream;
++import java.io.File;
++import java.io.FileInputStream;
++import java.io.FileOutputStream;
++import java.io.OutputStream;
++import java.util.Calendar;
++
++import javax.jcr.ImportUUIDBehavior;
++import javax.jcr.Node;
++import javax.jcr.Value;
++
++/**
++ * Created by The eXo Platform SAS.
++ *
++ * <br/>Date:
++ *
++ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
++ * @version $Id: TestImportImage.java 111 2008-11-11 11:11:11Z serg $
++ */
++public class TestImportVersionedChild extends JcrAPIBaseTest
++{
++
++ Node testRoot;
++
++ public void setUp() throws Exception
++ {
++ super.setUp();
++ testRoot = this.root.addNode("parent", "nt:folder");
++ root.save();
++ }
++
++ public void tearDown() throws Exception
++ {
++ testRoot.remove();
++ root.save();
++ super.tearDown();
++ }
++
++ protected void loadTestTree() throws Exception
++ {
++ // wc1/medias/picture
++ Node wc1 = testRoot.addNode("wc1", "nt:folder");
++ wc1.addMixin("mix:versionable");
++ testRoot.save();
++ Node medias = wc1.addNode("medias", "nt:folder");
++
++ Node picture = medias.addNode("picture", "nt:file");
++ picture.addMixin("mix:versionable");
++
++ Node res = picture.addNode("jcr:content", "nt:resource");
++ res.setProperty("jcr:lastModified", Calendar.getInstance());
++ res.setProperty("jcr:data", new ByteArrayInputStream("bla bla".getBytes()));
++ MimeTypeResolver mimres = new MimeTypeResolver();
++ res.setProperty("jcr:mimeType", mimres.getMimeType("screen.txt"));
++ root.save();
++ }
++
++ public void testImportVersionHistory() throws Exception
++ {
++ loadTestTree();
++ Node wc1 = (NodeImpl)session.getItem("/parent/wc1");
++
++ // make checkin/checkout a lot
++ wc1.checkin();
++ wc1.checkout();
++
++ // export import version history and node
++ File export = new File("F:\\temp\\export.xml");
++ File vhexport = new File("F:\\temp\\vhexport.xml");
++
++ OutputStream out = new FileOutputStream(export);
++ session.exportSystemView("/parent/wc1", out, false, false);
++
++ OutputStream vhout = new FileOutputStream(vhexport);
++ session.exportSystemView(wc1.getVersionHistory().getPath(), vhout, false, false);
++
++ // prepare data for version import
++ String versionHistory = wc1.getProperty("jcr:versionHistory").getValue().getString();
++ String baseVersion = wc1.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] jcrPredecessors = wc1.getProperty("jcr:predecessors").getValues();
++ StringBuilder jcrPredecessorsBuilder = new StringBuilder();
++ String[] predecessorsHistory;
++ for (Value value : jcrPredecessors)
++ {
++ if (jcrPredecessorsBuilder.length() > 0)
++ jcrPredecessorsBuilder.append(",");
++ jcrPredecessorsBuilder.append(value.getString());
++ }
++ if (jcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ predecessorsHistory = jcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ predecessorsHistory = new String[]{jcrPredecessorsBuilder.toString()};
++ }
++
++ // remember "picture" nodes version history data
++ Node picture = (NodeImpl)session.getItem("/parent/wc1/medias/picture");
++ String chversionHistory = picture.getProperty("jcr:versionHistory").getValue().getString();
++ String chbaseVersion = picture.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] chjcrPredecessors = picture.getProperty("jcr:predecessors").getValues();
++ StringBuilder chjcrPredecessorsBuilder = new StringBuilder();
++ String[] chpredecessorsHistory;
++ for (Value value : chjcrPredecessors)
++ {
++ if (chjcrPredecessorsBuilder.length() > 0)
++ chjcrPredecessorsBuilder.append(",");
++ chjcrPredecessorsBuilder.append(value.getString());
++ }
++ if (chjcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ chpredecessorsHistory = chjcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ chpredecessorsHistory = new String[]{chjcrPredecessorsBuilder.toString()};
++ }
++
++ // remove node
++ wc1.remove();
++ session.save();
++
++ out.close();
++ vhout.close();
++
++ // import
++ session.importXML("/parent", new FileInputStream(export), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW, true);
++
++ session.save();
++
++ wc1 = (NodeImpl)session.getItem("/parent/wc1");
++
++ VersionHistoryImporter versionHistoryImporter =
++ new VersionHistoryImporter((NodeImpl)wc1, new FileInputStream(vhexport), baseVersion, predecessorsHistory,
++ versionHistory);
++ versionHistoryImporter.doImport();
++ session.save();
++
++ picture = wc1.getNode("medias").getNode("picture");
++ assertTrue(picture.isNodeType("mix:versionable"));
++ assertEquals(chversionHistory, picture.getProperty("jcr:versionHistory").getValue().getString());
++ assertEquals(chbaseVersion, picture.getProperty("jcr:baseVersion").getValue().getString());
++ assertEquals(chpredecessorsHistory[0], picture.getProperty("jcr:predecessors").getValues()[0].getString());
++ }
++
++ public void testImportVersionHistoryPreloadChildVersionHistory() throws Exception
++ {
++ loadTestTree();
++ Node wc1 = (NodeImpl)session.getItem("/parent/wc1");
++ Node picture = (NodeImpl)session.getItem("/parent/wc1/medias/picture");
++
++ // make checkin/checkout a lot
++
++ wc1.checkin();
++ wc1.checkout();
++
++ picture.checkin();
++ picture.checkout();
++
++ // export import version history and node
++ File export = new File("F:\\temp\\export.xml");
++ File vhexport = new File("F:\\temp\\vhexport.xml");
++ File childvhexport = new File("F:\\temp\\childvhexport.xml");
++
++ OutputStream out = new FileOutputStream(export);
++ session.exportSystemView("/parent/wc1", out, false, false);
++
++ OutputStream childvhout = new FileOutputStream(childvhexport);
++ session.exportSystemView(picture.getVersionHistory().getPath(), childvhout, false, false);
++
++ OutputStream vhout = new FileOutputStream(vhexport);
++ session.exportSystemView(wc1.getVersionHistory().getPath(), vhout, false, false);
++
++ // prepare data for version import
++
++ String versionHistory = wc1.getProperty("jcr:versionHistory").getValue().getString();
++ String baseVersion = wc1.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] jcrPredecessors = wc1.getProperty("jcr:predecessors").getValues();
++ StringBuilder jcrPredecessorsBuilder = new StringBuilder();
++ String[] predecessorsHistory;
++ for (Value value : jcrPredecessors)
++ {
++ if (jcrPredecessorsBuilder.length() > 0)
++ jcrPredecessorsBuilder.append(",");
++ jcrPredecessorsBuilder.append(value.getString());
++ }
++ if (jcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ predecessorsHistory = jcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ predecessorsHistory = new String[]{jcrPredecessorsBuilder.toString()};
++ }
++
++ // prepare data for child version import
++
++ String chversionHistory = picture.getProperty("jcr:versionHistory").getValue().getString();
++ String chbaseVersion = picture.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] chjcrPredecessors = picture.getProperty("jcr:predecessors").getValues();
++ StringBuilder chjcrPredecessorsBuilder = new StringBuilder();
++ String[] chpredecessorsHistory;
++ for (Value value : chjcrPredecessors)
++ {
++ if (chjcrPredecessorsBuilder.length() > 0)
++ chjcrPredecessorsBuilder.append(",");
++ chjcrPredecessorsBuilder.append(value.getString());
++ }
++ if (chjcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ chpredecessorsHistory = chjcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ chpredecessorsHistory = new String[]{chjcrPredecessorsBuilder.toString()};
++ }
++
++ // remove node
++ wc1.remove();
++ session.save();
++
++ out.close();
++ vhout.close();
++
++ // import
++ session.importXML("/parent", new FileInputStream(export), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW, true);
++
++ session.save();
++
++ wc1 = (NodeImpl)session.getItem("/parent/wc1");
++ picture = wc1.getNode("medias").getNode("picture");
++
++ VersionHistoryImporter chversionHistoryImporter =
++ new VersionHistoryImporter((NodeImpl)picture, new FileInputStream(childvhexport), chbaseVersion,
++ chpredecessorsHistory, chversionHistory);
++ chversionHistoryImporter.doImport();
++ session.save();
++
++ VersionHistoryImporter versionHistoryImporter =
++ new VersionHistoryImporter((NodeImpl)wc1, new FileInputStream(vhexport), baseVersion, predecessorsHistory,
++ versionHistory);
++ versionHistoryImporter.doImport();
++ session.save();
++
++ assertTrue(picture.isNodeType("mix:versionable"));
++ assertEquals(chversionHistory, picture.getProperty("jcr:versionHistory").getValue().getString());
++ assertEquals(chbaseVersion, picture.getProperty("jcr:baseVersion").getValue().getString());
++ assertEquals(chpredecessorsHistory[0], picture.getProperty("jcr:predecessors").getValues()[0].getString());
++ }
++
++ /**
++ * Many mix:versionable subnodes.
++ * @throws Exception
++ */
++ public void testImportVersionHistoryWithManySubversions() throws Exception
++ {
++
++ // wc1/medias/picture
++ Node wc1 = testRoot.addNode("wc1", "nt:folder");
++ wc1.addMixin("mix:versionable");
++ testRoot.save();
++ Node medias = wc1.addNode("medias", "nt:folder");
++
++ Node picture = medias.addNode("picture", "nt:file");
++ picture.addMixin("mix:versionable");
++
++ Node res = picture.addNode("jcr:content", "nt:resource");
++ res.setProperty("jcr:lastModified", Calendar.getInstance());
++ res.setProperty("jcr:data", new ByteArrayInputStream("bla bla".getBytes()));
++ MimeTypeResolver mimres = new MimeTypeResolver();
++ res.setProperty("jcr:mimeType", mimres.getMimeType("screen.txt"));
++ root.save();
++
++ Node subNode1 = medias.addNode("subnode1", "nt:folder");
++ subNode1.addMixin("mix:versionable");
++ root.save();
++
++ Node subNode2 = subNode1.addNode("subnode2", "nt:folder");
++ Node subNode3 = subNode2.addNode("subnode3", "nt:folder");
++ subNode3.addMixin("mix:versionable");
++ root.save();
++
++ Node subNode4 = subNode3.addNode("subnode4", "nt:folder");
++ subNode4.addMixin("mix:versionable");
++ root.save();
++
++ // /medias/subnode1/subnode2/subnode3/subnode4
++ wc1.checkin();
++ wc1.checkout();
++
++ picture.checkin();
++ picture.checkout();
++
++ subNode1.checkin();
++ subNode1.checkout();
++
++ subNode4.checkin();
++ subNode4.checkout();
++
++ subNode3.checkin();
++ subNode3.checkout();
++
++ //TODO file path!!!!!!
++ // export import version history and node
++ File export = new File("F:\\temp\\export.xml");
++ File vhexport = new File("F:\\temp\\vhexport.xml");
++
++ OutputStream out = new FileOutputStream(export);
++ session.exportSystemView("/parent/wc1", out, false, false);
++
++ OutputStream vhout = new FileOutputStream(vhexport);
++ session.exportSystemView(wc1.getVersionHistory().getPath(), vhout, false, false);
++
++ // prepare data for version import
++
++ String versionHistory = wc1.getProperty("jcr:versionHistory").getValue().getString();
++ String baseVersion = wc1.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] jcrPredecessors = wc1.getProperty("jcr:predecessors").getValues();
++ StringBuilder jcrPredecessorsBuilder = new StringBuilder();
++ String[] predecessorsHistory;
++ for (Value value : jcrPredecessors)
++ {
++ if (jcrPredecessorsBuilder.length() > 0)
++ jcrPredecessorsBuilder.append(",");
++ jcrPredecessorsBuilder.append(value.getString());
++ }
++ if (jcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ predecessorsHistory = jcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ predecessorsHistory = new String[]{jcrPredecessorsBuilder.toString()};
++ }
++
++ // prepare data for child version import
++
++ String chversionHistory = subNode4.getProperty("jcr:versionHistory").getValue().getString();
++ String chbaseVersion = subNode4.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] chjcrPredecessors = subNode4.getProperty("jcr:predecessors").getValues();
++ StringBuilder chjcrPredecessorsBuilder = new StringBuilder();
++ String[] chpredecessorsHistory;
++ for (Value value : chjcrPredecessors)
++ {
++ if (chjcrPredecessorsBuilder.length() > 0)
++ chjcrPredecessorsBuilder.append(",");
++ chjcrPredecessorsBuilder.append(value.getString());
++ }
++ if (chjcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ chpredecessorsHistory = chjcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ chpredecessorsHistory = new String[]{chjcrPredecessorsBuilder.toString()};
++ }
++
++ // remove node
++ wc1.remove();
++ session.save();
++
++ out.close();
++ vhout.close();
++
++ // import
++ session.importXML("/parent", new FileInputStream(export), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW, true);
++
++ session.save();
++
++ wc1 = (NodeImpl)session.getItem("/parent/wc1");
++
++ subNode4 = (NodeImpl)session.getItem("/parent/wc1/medias/subnode1/subnode2/subnode3/subnode4");
++
++ VersionHistoryImporter versionHistoryImporter =
++ new VersionHistoryImporter((NodeImpl)wc1, new FileInputStream(vhexport), baseVersion, predecessorsHistory,
++ versionHistory);
++ versionHistoryImporter.doImport();
++ session.save();
++
++ assertTrue(subNode4.isNodeType("mix:versionable"));
++ assertEquals(chversionHistory, subNode4.getProperty("jcr:versionHistory").getValue().getString());
++ assertEquals(chbaseVersion, subNode4.getProperty("jcr:baseVersion").getValue().getString());
++ assertEquals(chpredecessorsHistory[0], subNode4.getProperty("jcr:predecessors").getValues()[0].getString());
++ }
++
++ public void testImportVersionHistoryManyVersions() throws Exception
++ {
++ // wc1/medias/picture
++ Node wc1 = testRoot.addNode("wc1", "nt:folder");
++ wc1.addMixin("mix:versionable");
++ testRoot.save();
++ Node medias = wc1.addNode("medias", "nt:folder");
++
++ Node picture = medias.addNode("picture", "nt:file");
++ picture.addMixin("mix:versionable");
++
++ Node res = picture.addNode("jcr:content", "nt:resource");
++ res.setProperty("jcr:lastModified", Calendar.getInstance());
++ res.setProperty("jcr:data", new ByteArrayInputStream("bla bla".getBytes()));
++ MimeTypeResolver mimres = new MimeTypeResolver();
++ res.setProperty("jcr:mimeType", mimres.getMimeType("screen.txt"));
++ root.save();
++
++ // make checkin/checkout a lot
++ wc1.checkin();
++ wc1.checkout();
++
++ picture.checkin();
++ picture.checkout();
++
++ res.setProperty("jcr:data", new ByteArrayInputStream("new data".getBytes()));
++ root.save();
++
++ picture.checkin();
++ picture.checkout();
++
++ // check before import
++
++ picture.restore("1", true);
++ String strvalue = picture.getNode("jcr:content").getProperty("jcr:data").getString();
++ assertEquals("bla bla", strvalue);
++
++ picture.restore("2", true);
++ strvalue = picture.getNode("jcr:content").getProperty("jcr:data").getString();
++ assertEquals("new data", strvalue);
++
++ picture.checkout();
++
++ // make new version
++ assertTrue(picture.getProperty("jcr:isCheckedOut").getValue().getBoolean());
++
++ // export import version history and node
++ File export = new File("F:\\temp\\export.xml");
++ File vhexport = new File("F:\\temp\\vhexport.xml");
++
++ OutputStream out = new FileOutputStream(export);
++ session.exportSystemView("/parent/wc1", out, false, false);
++
++ OutputStream vhout = new FileOutputStream(vhexport);
++ session.exportSystemView(wc1.getVersionHistory().getPath(), vhout, false, false);
++
++ // prepare data for version import
++
++ String versionHistory = wc1.getProperty("jcr:versionHistory").getValue().getString();
++ String baseVersion = wc1.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] jcrPredecessors = wc1.getProperty("jcr:predecessors").getValues();
++ StringBuilder jcrPredecessorsBuilder = new StringBuilder();
++ String[] predecessorsHistory;
++ for (Value value : jcrPredecessors)
++ {
++ if (jcrPredecessorsBuilder.length() > 0)
++ jcrPredecessorsBuilder.append(",");
++ jcrPredecessorsBuilder.append(value.getString());
++ }
++ if (jcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ predecessorsHistory = jcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ predecessorsHistory = new String[]{jcrPredecessorsBuilder.toString()};
++ }
++
++ String childVersionHistory = picture.getProperty("jcr:versionHistory").getValue().getString();
++ String childBaseVersion = picture.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] childJcrPredecessors = picture.getProperty("jcr:predecessors").getValues();
++ StringBuilder childJcrPredecessorsBuilder = new StringBuilder();
++ String[] childPredecessorsHistory;
++ for (Value value : childJcrPredecessors)
++ {
++ if (childJcrPredecessorsBuilder.length() > 0)
++ childJcrPredecessorsBuilder.append(",");
++ childJcrPredecessorsBuilder.append(value.getString());
++ }
++ if (childJcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ childPredecessorsHistory = childJcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ childPredecessorsHistory = new String[]{childJcrPredecessorsBuilder.toString()};
++ }
++
++ String chversionHistory = picture.getProperty("jcr:versionHistory").getValue().getString();
++ String chbaseVersion = picture.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] chjcrPredecessors = picture.getProperty("jcr:predecessors").getValues();
++ StringBuilder chjcrPredecessorsBuilder = new StringBuilder();
++ String[] chpredecessorsHistory;
++ for (Value value : chjcrPredecessors)
++ {
++ if (chjcrPredecessorsBuilder.length() > 0)
++ chjcrPredecessorsBuilder.append(",");
++ chjcrPredecessorsBuilder.append(value.getString());
++ }
++ if (chjcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ chpredecessorsHistory = chjcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ chpredecessorsHistory = new String[]{chjcrPredecessorsBuilder.toString()};
++ }
++
++ // remove node
++ wc1.remove();
++ session.save();
++
++ out.close();
++ vhout.close();
++
++ // import
++ session.importXML("/parent", new FileInputStream(export), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW, true);
++
++ session.save();
++
++ wc1 = (NodeImpl)session.getItem("/parent/wc1");
++
++ VersionHistoryImporter versionHistoryImporter =
++ new VersionHistoryImporter((NodeImpl)wc1, new FileInputStream(vhexport), baseVersion, predecessorsHistory,
++ versionHistory);
++ versionHistoryImporter.doImport();
++ session.save();
++
++ picture = wc1.getNode("medias").getNode("picture");
++ assertTrue(picture.isNodeType("mix:versionable"));
++ assertEquals(chversionHistory, picture.getProperty("jcr:versionHistory").getValue().getString());
++ assertEquals(chbaseVersion, picture.getProperty("jcr:baseVersion").getValue().getString());
++ assertEquals(chpredecessorsHistory[0], picture.getProperty("jcr:predecessors").getValues()[0].getString());
++ assertTrue(picture.getProperty("jcr:isCheckedOut").getValue().getBoolean());
++
++ String value = picture.getNode("jcr:content").getProperty("jcr:data").getString();
++ assertEquals("new data", value);
++
++ picture.restore("1", true);
++ value = picture.getNode("jcr:content").getProperty("jcr:data").getString();
++ assertEquals("bla bla", value);
++
++ picture.restore("2", true);
++ value = picture.getNode("jcr:content").getProperty("jcr:data").getString();
++ assertEquals("new data", value);
++
++ picture.checkout();
++
++ // make new version
++ assertTrue(picture.getProperty("jcr:isCheckedOut").getValue().getBoolean());
++ res = picture.getNode("jcr:content");
++ res.setProperty("jcr:data", new ByteArrayInputStream("third".getBytes()));
++ root.save();
++
++ picture.checkin();
++ picture.checkout();
++
++ picture.restore("1", true);
++ value = picture.getNode("jcr:content").getProperty("jcr:data").getString();
++ assertEquals("bla bla", value);
++
++ picture.restore("3", true);
++ value = picture.getNode("jcr:content").getProperty("jcr:data").getString();
++ assertEquals("third", value);
++ }
++
++ /**
++ * Many mix:versionable subnodes.
++ * @throws Exception
++ */
++ public void testImportVersionHistoryWithManyVersions() throws Exception
++ {
++
++ // wc1/medias/picture
++ Node wc1 = testRoot.addNode("wc1", "nt:folder");
++ wc1.addMixin("mix:versionable");
++ testRoot.save();
++ Node medias = wc1.addNode("medias", "nt:folder");
++
++ Node picture = medias.addNode("picture", "nt:file");
++ picture.addMixin("mix:versionable");
++
++ Node res = picture.addNode("jcr:content", "nt:resource");
++ res.setProperty("jcr:lastModified", Calendar.getInstance());
++ res.setProperty("jcr:data", new ByteArrayInputStream("bla bla".getBytes()));
++ MimeTypeResolver mimres = new MimeTypeResolver();
++ res.setProperty("jcr:mimeType", mimres.getMimeType("screen.txt"));
++ root.save();
++
++ wc1.checkin();
++ wc1.checkout();
++
++ wc1.checkin();
++ wc1.checkout();
++
++ // picture.checkin();
++ // picture.checkout();
++
++ //TODO file path!!!!!!
++ // export import version history and node
++ File export = new File("F:\\temp\\export.xml");
++ File vhexport = new File("F:\\temp\\vhexport.xml");
++
++ OutputStream out = new FileOutputStream(export);
++ session.exportSystemView("/parent/wc1", out, false, false);
++
++ OutputStream vhout = new FileOutputStream(vhexport);
++ session.exportSystemView(wc1.getVersionHistory().getPath(), vhout, false, false);
++
++ // prepare data for version import
++
++ String versionHistory = wc1.getProperty("jcr:versionHistory").getValue().getString();
++ String baseVersion = wc1.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] jcrPredecessors = wc1.getProperty("jcr:predecessors").getValues();
++ StringBuilder jcrPredecessorsBuilder = new StringBuilder();
++ String[] predecessorsHistory;
++ for (Value value : jcrPredecessors)
++ {
++ if (jcrPredecessorsBuilder.length() > 0)
++ jcrPredecessorsBuilder.append(",");
++ jcrPredecessorsBuilder.append(value.getString());
++ }
++ if (jcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ predecessorsHistory = jcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ predecessorsHistory = new String[]{jcrPredecessorsBuilder.toString()};
++ }
++ // remove node
++ wc1.remove();
++ session.save();
++
++ out.close();
++ vhout.close();
++
++ // import
++ session.importXML("/parent", new FileInputStream(export), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW, true);
++
++ session.save();
++
++ wc1 = (NodeImpl)session.getItem("/parent/wc1");
++ picture = wc1.getNode("medias").getNode("picture");
++
++ VersionHistoryImporter versionHistoryImporter =
++ new VersionHistoryImporter((NodeImpl)wc1, new FileInputStream(vhexport), baseVersion, predecessorsHistory,
++ versionHistory);
++ versionHistoryImporter.doImport();
++ session.save();
++
++ assertTrue(picture.isNodeType("mix:versionable"));
++ }
++
++ public void testImportVersionHistoryNonSysWorkspace() throws Exception
++ {
++
++ SessionImpl session = (SessionImpl)this.repository.login(credentials, "ws1");
++
++ Node root = session.getRootNode();
++ Node testRoot = root.addNode("parent", "nt:folder");
++ root.save();
++
++ try
++ {
++ // wc1/medias/picture
++ Node wc1 = testRoot.addNode("wc1", "nt:folder");
++ wc1.addMixin("mix:versionable");
++ testRoot.save();
++ Node medias = wc1.addNode("medias", "nt:folder");
++
++ Node picture = medias.addNode("picture", "nt:file");
++ picture.addMixin("mix:versionable");
++
++ Node res = picture.addNode("jcr:content", "nt:resource");
++ res.setProperty("jcr:lastModified", Calendar.getInstance());
++ res.setProperty("jcr:data", new ByteArrayInputStream("bla bla".getBytes()));
++ MimeTypeResolver mimres = new MimeTypeResolver();
++ res.setProperty("jcr:mimeType", mimres.getMimeType("screen.txt"));
++ root.save();
++
++ // make checkin/checkout a lot
++
++ wc1.checkin();
++ wc1.checkout();
++
++ // export import version history and node
++ File export = new File("F:\\temp\\export.xml");
++ File vhexport = new File("F:\\temp\\vhexport.xml");
++
++ OutputStream out = new FileOutputStream(export);
++ session.exportSystemView("/parent/wc1", out, false, false);
++
++ OutputStream vhout = new FileOutputStream(vhexport);
++ session.exportSystemView(wc1.getVersionHistory().getPath(), vhout, false, false);
++
++ // prepare data for version import
++
++ String versionHistory = wc1.getProperty("jcr:versionHistory").getValue().getString();
++ String baseVersion = wc1.getProperty("jcr:baseVersion").getValue().getString();
++ Value[] jcrPredecessors = wc1.getProperty("jcr:predecessors").getValues();
++ StringBuilder jcrPredecessorsBuilder = new StringBuilder();
++ String[] predecessorsHistory;
++ for (Value value : jcrPredecessors)
++ {
++ if (jcrPredecessorsBuilder.length() > 0)
++ jcrPredecessorsBuilder.append(",");
++ jcrPredecessorsBuilder.append(value.getString());
++ }
++ if (jcrPredecessorsBuilder.toString().indexOf(",") > -1)
++ {
++ predecessorsHistory = jcrPredecessorsBuilder.toString().split(",");
++ }
++ else
++ {
++ predecessorsHistory = new String[]{jcrPredecessorsBuilder.toString()};
++ }
++
++ // remove node
++ wc1.remove();
++ session.save();
++
++ out.close();
++ vhout.close();
++
++ // import
++ session.importXML("/parent", new FileInputStream(export), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW, true);
++
++ session.save();
++
++ wc1 = (NodeImpl)session.getItem("/parent/wc1");
++
++ VersionHistoryImporter versionHistoryImporter =
++ new VersionHistoryImporter((NodeImpl)wc1, new FileInputStream(vhexport), baseVersion, predecessorsHistory,
++ versionHistory);
++ versionHistoryImporter.doImport();
++ session.save();
++
++ picture = wc1.getNode("medias").getNode("picture");
++ assertTrue(picture.isNodeType("mix:versionable"));
++ }
++ finally
++ {
++ testRoot.remove();
++ root.save();
++ session.logout();
++ }
++ }
++
++}
+\ No newline at end of file
13 years, 3 months
exo-jcr SVN: r3983 - jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-02-17 09:00:07 -0500 (Thu, 17 Feb 2011)
New Revision: 3983
Modified:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml
Log:
EXOJCR-1193: Index retrieval from coordinator node
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml 2011-02-17 13:59:44 UTC (rev 3982)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml 2011-02-17 14:00:07 UTC (rev 3983)
@@ -100,8 +100,9 @@
<property name="jgroups-multiplexer-stack" value="true" />
<property name="jbosscache-cluster-name" value="JCR-cluster-indexer-ws" />
<property name="max-volatile-time" value="60" />
- <property name="rdbms-reindexing" value="false" />
+ <property name="rdbms-reindexing" value="true" />
<property name="reindexing-page-size" value="1000" />
+ <property name="index-recovery-mode" value="from-coordinator" />
</properties>
</query-handler>
</workspace></programlisting> <table>
@@ -171,6 +172,16 @@
storage for re-indexing purpose, the default value is
100</entry>
</row>
+
+ <row>
+ <entry>index-recovery-mode</entry>
+
+ <entry>If the parameter has been set to
+ <command>from-indexing</command>, so a full indexing will be
+ automatically launched (default behavior), if the parameter
+ has been set to <command>from-coordinator</command>, the index
+ will be retrieved from coordinator</entry>
+ </row>
</tbody>
</tgroup>
</table></para>
13 years, 3 months
exo-jcr SVN: r3982 - in jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl: rdbms and 1 other directory.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-02-17 08:59:44 -0500 (Thu, 17 Feb 2011)
New Revision: 3982
Modified:
jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedRepositoryRestoreSameConfig.java
jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedWorkspaceRestoreSameConfig.java
jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/rdbms/FullBackupJob.java
Log:
EXOJCR-1193: Index retrieval from coordinator node
Modified: jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedRepositoryRestoreSameConfig.java
===================================================================
--- jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedRepositoryRestoreSameConfig.java 2011-02-17 13:57:37 UTC (rev 3981)
+++ jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedRepositoryRestoreSameConfig.java 2011-02-17 13:59:44 UTC (rev 3982)
@@ -115,7 +115,7 @@
for (Suspendable component : suspendableComponents)
{
- component.suspend();
+ component.suspend(Suspendable.SUSPEND_COMPONENT_ON_ALL_NODES);
resumeComponents.add(component);
}
}
Modified: jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedWorkspaceRestoreSameConfig.java
===================================================================
--- jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedWorkspaceRestoreSameConfig.java 2011-02-17 13:57:37 UTC (rev 3981)
+++ jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/JobExistedWorkspaceRestoreSameConfig.java 2011-02-17 13:59:44 UTC (rev 3982)
@@ -82,7 +82,7 @@
for (Suspendable component : suspendableComponents)
{
- component.suspend();
+ component.suspend(Suspendable.SUSPEND_COMPONENT_ON_ALL_NODES);
resumeComponents.add(component);
}
Modified: jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/rdbms/FullBackupJob.java
===================================================================
--- jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/rdbms/FullBackupJob.java 2011-02-17 13:57:37 UTC (rev 3981)
+++ jcr/trunk/exo.jcr.component.ext/src/main/java/org/exoplatform/services/jcr/ext/backup/impl/rdbms/FullBackupJob.java 2011-02-17 13:59:44 UTC (rev 3982)
@@ -129,7 +129,7 @@
// suspend all components
for (Suspendable component : suspendableComponents)
{
- component.suspend();
+ component.suspend(Suspendable.SUSPEND_COMPONENT_ON_ALL_NODES);
resumeComponents.add(component);
}
13 years, 3 months
exo-jcr SVN: r3981 - in jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr: impl/backup and 4 other directories.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-02-17 08:57:37 -0500 (Thu, 17 Feb 2011)
New Revision: 3981
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieve.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieveImpl.java
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/Suspendable.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/io/DirectoryHelper.java
Log:
EXOJCR-1193: Index retrieval from coordinator node
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -112,4 +112,6 @@
public static final String PARAM_REINDEXING_PAGE_SIZE = "reindexing-page-size";
public static final String PARAM_RDBMS_REINDEXING = "rdbms-reindexing";
+
+ public static final String PARAM_INDEX_RECOVERY_MODE = "index-recovery-mode";
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/Suspendable.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/Suspendable.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/Suspendable.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -24,13 +24,16 @@
*/
public interface Suspendable
{
+ public static int SUSPEND_COMPONENT_ON_ALL_NODES = 1;
+ public static int SUSPEND_COMPONENT_ON_OTHERS_NODES_ONLY = 2;
+
/**
* Suspend component.
*
* @throws SuspendException of error occurred
*/
- void suspend() throws SuspendException;
+ void suspend(int flag) throws SuspendException;
/**
* Resume component.
Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieve.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieve.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieve.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.query;
+
+import java.io.InputStream;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * Date: 16.02.2011
+ *
+ * @author <a href="mailto:anatoliy.bazko@exoplatform.com.ua">Anatoliy Bazko</a>
+ * @version $Id: IndexRetrieve.java 34360 2010-11-11 11:11:11Z tolusha $
+ */
+public interface IndexRetrieve
+{
+ /**
+ * Get list of relative paths of all files from index directory.
+ *
+ * @return List
+ * @throws RepositoryException
+ * if any exception occurred
+ */
+ public List<String> getIndexList() throws RepositoryException;
+
+ /**
+ * Get input stream of index file.
+ * @param filePath
+ * String, relative file path
+ * @return InputStream
+ * @throws RepositoryException
+ * if any exception occurred
+ */
+ public InputStream getIndexFile(String filePath) throws RepositoryException;
+}
Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieveImpl.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieveImpl.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexRetrieveImpl.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.query;
+
+import org.exoplatform.commons.utils.PrivilegedFileHelper;
+import org.exoplatform.services.jcr.impl.util.io.DirectoryHelper;
+import org.exoplatform.services.rpc.RPCException;
+import org.exoplatform.services.rpc.RPCService;
+import org.exoplatform.services.rpc.RemoteCommand;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * Date: 16.02.2011
+ *
+ * @author <a href="mailto:anatoliy.bazko@exoplatform.com.ua">Anatoliy Bazko</a>
+ * @version $Id: IndexRetrieveImpl.java 34360 2010-11-11 11:11:11Z tolusha $
+ */
+public class IndexRetrieveImpl implements IndexRetrieve
+{
+
+ /**
+ * Buffer size.
+ */
+ public static final int BUFFER_SIZE = 1024 * 1024;
+
+ /**
+ * The service for executing commands on all nodes of cluster.
+ */
+ protected final RPCService rpcService;
+
+ /**
+ * Remote command responsible for getting the list of relative paths of all files from index directory.
+ */
+ private RemoteCommand getIndexList;
+
+ /**
+ * Remote command responsible for getting data of target file.
+ */
+ private RemoteCommand getIndexFile;
+
+ /**
+ * Constructor IndexRetrieveImpl.
+ */
+ public IndexRetrieveImpl(RPCService rpcService, final String wsId, final boolean isSystem, final File indexDirectory)
+ {
+ this.rpcService = rpcService;
+
+ getIndexList = rpcService.registerCommand(new RemoteCommand()
+ {
+ public String getId()
+ {
+ return "org.exoplatform.services.jcr.impl.core.query.IndexRetrieveImpl-getIndexList-" + wsId + "-"
+ + isSystem;
+ }
+
+ public Serializable execute(Serializable[] args) throws Throwable
+ {
+ int indexDirLen = PrivilegedFileHelper.getAbsolutePath(indexDirectory).length();
+
+ StringBuilder result = new StringBuilder();
+ for (File file : DirectoryHelper.listFiles(indexDirectory))
+ {
+ if (!file.isDirectory())
+ {
+ result.append(PrivilegedFileHelper.getAbsolutePath(file).substring(indexDirLen)).append('\n');
+ }
+ }
+
+ return result.toString();
+ }
+ });
+
+ getIndexFile = rpcService.registerCommand(new RemoteCommand()
+ {
+ public String getId()
+ {
+ return "org.exoplatform.services.jcr.impl.core.query.IndexRetrieveImpl-getIndexFile-" + wsId + "-"
+ + isSystem;
+ }
+
+ public Serializable execute(Serializable[] args) throws Throwable
+ {
+ String filePath = (String)args[0];
+ int offset = (Integer)args[1];
+
+ RandomAccessFile file = new RandomAccessFile(new File(indexDirectory, filePath), "r");
+ file.seek(offset);
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int len = file.read(buffer);
+
+ if (len == -1)
+ {
+ return null;
+ }
+ else
+ {
+ byte[] data = new byte[len];
+ System.arraycopy(buffer, 0, data, 0, len);
+
+ return data;
+ }
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<String> getIndexList() throws RepositoryException
+ {
+ try
+ {
+ List<String> result = new ArrayList<String>();
+
+ String data = (String)rpcService.executeCommandOnCoordinator(getIndexList, true);
+ String[] files = data.split("\n");
+
+ for (String file : files)
+ {
+ result.add(file);
+ }
+
+ return result;
+ }
+ catch (SecurityException e)
+ {
+ throw new RepositoryException(e);
+ }
+ catch (RPCException e)
+ {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public InputStream getIndexFile(String filePath) throws RepositoryException
+ {
+ try
+ {
+ return new RemoteInputStream(filePath);
+ }
+ catch (SecurityException e)
+ {
+ throw new RepositoryException(e);
+ }
+ catch (RPCException e)
+ {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Allows to read data from remote machine.
+ */
+ class RemoteInputStream extends InputStream
+ {
+ private final String filePath;
+
+ private int fileOffset = 0;
+
+ private int bufferOffset = 0;
+
+ private byte[] buffer;
+
+ RemoteInputStream(String filePath) throws SecurityException, RPCException
+ {
+ this.filePath = filePath;
+ readNext();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int read() throws IOException
+ {
+ throw new UnsupportedOperationException(
+ "RemoteStream.read(byte b[], int off, int len) method is not supported");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int available() throws IOException
+ {
+ return buffer == null ? 0 : buffer.length - bufferOffset;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int read(byte b[]) throws IOException
+ {
+ if (buffer == null)
+ {
+ return -1;
+ }
+ else if (available() == 0)
+ {
+ try
+ {
+ readNext();
+
+ if (buffer == null)
+ {
+ return -1;
+ }
+ }
+ catch (SecurityException e)
+ {
+ throw new IOException(e);
+ }
+ catch (RPCException e)
+ {
+ throw new IOException(e);
+ }
+ }
+
+ int len = Math.min(b.length, available());
+ System.arraycopy(buffer, bufferOffset, b, 0, len);
+ bufferOffset += len;
+
+ return len;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int read(byte b[], int off, int len) throws IOException
+ {
+ throw new UnsupportedOperationException(
+ "RemoteStream.read(byte b[], int off, int len) method is not supported");
+ }
+
+ private void readNext() throws SecurityException, RPCException
+ {
+ this.buffer = (byte[])rpcService.executeCommandOnCoordinator(getIndexFile, true, filePath, fileOffset);
+ if (buffer != null)
+ {
+ this.fileOffset += this.buffer.length;
+ this.bufferOffset = 0;
+ }
+ }
+ }
+}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -78,6 +78,11 @@
*/
private final WorkspaceContainerFacade container;
+ /**
+ * The class responsible for index retrieving from other place.
+ */
+ private final IndexRetrieve indexRetrieve;
+
/**
* Creates a new context instance.
*
@@ -100,12 +105,15 @@
* @param excludedNodeId
* id of the node that should be excluded from indexing. Any
* descendant of that node is also excluded from indexing.
+ * @param indexRetrieve
+ * the index retriever from other place
*/
public QueryHandlerContext(WorkspaceContainerFacade container, ItemDataConsumer stateMgr, IndexingTree indexingTree,
NodeTypeDataManager nodeTypeDataManager, NamespaceRegistryImpl nsRegistry, QueryHandler parentHandler,
String indexDirectory, DocumentReaderService extractor, boolean createInitialIndex,
- LuceneVirtualTableResolver virtualTableResolver)
+ LuceneVirtualTableResolver virtualTableResolver, IndexRetrieve indexRetrieve)
{
+ this.indexRetrieve = indexRetrieve;
this.container = container;
this.stateMgr = stateMgr;
this.indexingTree = indexingTree;
@@ -223,4 +231,10 @@
{
return indexDirectory;
}
+
+ public IndexRetrieve getIndexRetrieve()
+ {
+ return indexRetrieve;
+ }
+
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -194,5 +194,9 @@
{
searchIndex.setRDBMSReindexing(Boolean.parseBoolean(value));
}
+ else if (QueryHandlerParams.PARAM_INDEX_RECOVERY_MODE.equals(name))
+ {
+ searchIndex.setIndexRecoveryMode(value);
+ }
}
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -167,6 +167,9 @@
*/
protected final String workspaceName;
+ /**
+ * The repository service.
+ */
protected final RepositoryService rService;
/**
@@ -175,7 +178,7 @@
protected final String wsId;
/**
- * The service for executing commands on all nodes of cluster.
+ * Component responsible for executing commands in cluster nodes.
*/
protected final RPCService rpcService;
@@ -190,6 +193,11 @@
protected Boolean isResponsibleForResuming = false;
/**
+ * Suspend flag.
+ */
+ protected Integer suspendFlag;
+
+ /**
* Suspend remote command.
*/
private RemoteCommand suspend;
@@ -204,41 +212,13 @@
*/
private RemoteCommand requestForResponsibleForResuming;
- /**
- * Creates a new <code>SearchManager</code>.
- *
- * @param rEntry
- * repository configuration
- * @param rService
- * repository service
- * @param config
- * the search configuration.
- * @param nsReg
- * the namespace registry.
- * @param ntReg
- * the node type registry.
- * @param itemMgr
- * the shared item state manager.
- * @param rootNodeId
- * the id of the root node.
- * @param parentMgr
- * the parent search manager or <code>null</code> if there is no
- * parent search manager.
- * @param excludedNodeId
- * id of the node that should be excluded from indexing. Any
- * descendant of that node will also be excluded from indexing.
- * @throws RepositoryException
- * if the search manager cannot be initialized
- * @throws RepositoryConfigurationException
- */
-
- public SearchManager(WorkspaceEntry wsConfig, RepositoryEntry rEntry, RepositoryService rService,
+ public SearchManager(WorkspaceEntry wEntry, RepositoryEntry rEntry, RepositoryService rService,
QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
DocumentReaderService extractor, ConfigurationManager cfm, final RepositoryIndexSearcherHolder indexSearcherHolder)
throws RepositoryException, RepositoryConfigurationException
{
- this(wsConfig, rEntry, rService, config, nsReg, ntReg, itemMgr, parentSearchManager, extractor, cfm,
+ this(wEntry, rEntry, rService, config, nsReg, ntReg, itemMgr, parentSearchManager, extractor, cfm,
indexSearcherHolder, null);
}
@@ -271,19 +251,18 @@
* if the search manager cannot be initialized
* @throws RepositoryConfigurationException
*/
-
- public SearchManager(WorkspaceEntry wsConfig, RepositoryEntry rEntry, RepositoryService rService,
+ public SearchManager(WorkspaceEntry wEntry, RepositoryEntry rEntry, RepositoryService rService,
QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
DocumentReaderService extractor, ConfigurationManager cfm,
final RepositoryIndexSearcherHolder indexSearcherHolder, RPCService rpcService) throws RepositoryException,
RepositoryConfigurationException
{
+ this.rpcService = rpcService;
this.repositoryName = rEntry.getName();
- this.workspaceName = wsConfig.getName();
+ this.workspaceName = wEntry.getName();
this.rService = rService;
- this.rpcService = rpcService;
- this.wsId = wsConfig.getUniqueName();
+ this.wsId = wEntry.getUniqueName();
this.extractor = extractor;
indexSearcherHolder.addIndexSearcher(this);
this.config = config;
@@ -561,9 +540,6 @@
try
{
indexingRootData = (NodeData)itemMgr.getItemData(Constants.ROOT_UUID);
- // indexingRootData =
- // new TransientNodeData(Constants.ROOT_PATH, Constants.ROOT_UUID, 1, Constants.NT_UNSTRUCTURED,
- // new InternalQName[0], 0, null, new AccessControlList());
}
catch (RepositoryException e)
{
@@ -604,7 +580,7 @@
final ChangesHolder changes = getChanges(removedNodes, addedNodes);
apply(changes);
}
-
+
public void apply(ChangesHolder changes) throws RepositoryException, IOException
{
if (handler != null && changes != null && (!changes.getAdd().isEmpty() || !changes.getRemove().isEmpty()))
@@ -703,7 +679,7 @@
}
return null;
}
-
+
protected QueryHandlerContext createQueryHandlerContext(QueryHandler parentHandler)
throws RepositoryConfigurationException
{
@@ -717,9 +693,15 @@
throw new RepositoryConfigurationException(e);
}
+ IndexRetrieve indexRetrieve =
+ rpcService == null ? null : new IndexRetrieveImpl(rpcService, getWsId(), parentHandler == null,
+ getIndexDirectory());
+
QueryHandlerContext context =
new QueryHandlerContext(container, itemMgr, indexingTree, nodeTypeDataManager, nsReg, parentHandler,
- getIndexDirectory(), extractor, true, virtualTableResolver);
+ PrivilegedFileHelper.getAbsolutePath(getIndexDirectory()), extractor, true, virtualTableResolver,
+ indexRetrieve);
+
return context;
}
@@ -753,7 +735,10 @@
}
}
- protected String getIndexDir() throws RepositoryConfigurationException
+ /**^
+ * Returns "index-dir" parameter from configuration.
+ */
+ protected String getIndexDirParam() throws RepositoryConfigurationException
{
String dir = config.getParameterValue(QueryHandlerParams.PARAM_INDEX_DIR, null);
if (dir == null)
@@ -803,8 +788,8 @@
if (parentSearchManager != null)
{
newChangesFilter =
- constuctor.newInstance(this, parentSearchManager, config, indexingTree, parentSearchManager
- .getIndexingTree(), handler, parentSearchManager.getHandler(), cfm);
+ constuctor.newInstance(this, parentSearchManager, config, indexingTree,
+ parentSearchManager.getIndexingTree(), handler, parentSearchManager.getHandler(), cfm);
}
}
catch (SecurityException e)
@@ -1000,9 +985,10 @@
/**
* {@inheritDoc}
*/
- public void suspend() throws SuspendException
+ public void suspend(int flag) throws SuspendException
{
isResponsibleForResuming = true;
+ suspendFlag = flag;
if (rpcService != null)
{
@@ -1051,8 +1037,9 @@
}
isResponsibleForResuming = false;
+ suspendFlag = null;
}
-
+
/**
* Register remote commands.
*/
@@ -1064,7 +1051,8 @@
public String getId()
{
- return "org.exoplatform.services.jcr.impl.core.query.SearchManager-suspend-" + wsId;
+ return "org.exoplatform.services.jcr.impl.core.query.SearchManager-suspend-" + wsId + "-"
+ + (parentSearchManager == null);
}
public Serializable execute(Serializable[] args) throws Throwable
@@ -1079,7 +1067,8 @@
public String getId()
{
- return "org.exoplatform.services.jcr.impl.core.query.SearchManager-resume-" + wsId;
+ return "org.exoplatform.services.jcr.impl.core.query.SearchManager-resume-" + wsId + "-"
+ + (parentSearchManager == null);
}
public Serializable execute(Serializable[] args) throws Throwable
@@ -1095,7 +1084,7 @@
public String getId()
{
return "org.exoplatform.services.jcr.impl.core.query.SearchManager-requestForResponsibilityForResuming-"
- + wsId;
+ + wsId + "-" + (parentSearchManager == null);
}
public Serializable execute(Serializable[] args) throws Throwable
@@ -1109,35 +1098,33 @@
protected void suspendLocally() throws SuspendException
{
+ if (isResponsibleForResuming && suspendFlag == Suspendable.SUSPEND_COMPONENT_ON_OTHERS_NODES_ONLY)
+ {
+ return;
+ }
+
if (isSuspended)
{
throw new SuspendException("Component already suspended.");
}
isSuspended = true;
-
stop();
-
- if (handler instanceof Suspendable)
- {
- ((Suspendable)handler).suspend();
- }
}
protected void resumeLocally() throws ResumeException
{
- if (!isSuspended)
+ if (isResponsibleForResuming && suspendFlag == Suspendable.SUSPEND_COMPONENT_ON_OTHERS_NODES_ONLY)
{
- throw new ResumeException("Component is not suspended.");
+ return;
}
- start();
-
- if (handler instanceof Suspendable)
+ if (!isSuspended)
{
- ((Suspendable)handler).resume();
+ throw new ResumeException("Component is not suspended.");
}
+ start();
isSuspended = false;
}
@@ -1195,7 +1182,7 @@
{
try
{
- DirectoryHelper.removeDirectory(new File(getIndexDirectory()));
+ DirectoryHelper.removeDirectory(getIndexDirectory());
}
catch (IOException e)
{
@@ -1214,7 +1201,7 @@
{
try
{
- File indexDir = new File(getIndexDirectory());
+ File indexDir = getIndexDirectory();
if (!PrivilegedFileHelper.exists(indexDir))
{
@@ -1238,14 +1225,14 @@
}
/**
- * Return index directory.
+ * Returns the index directory.
*
- * @return String
+ * @return File
* @throws RepositoryConfigurationException
*/
- protected String getIndexDirectory() throws RepositoryConfigurationException
+ protected File getIndexDirectory() throws RepositoryConfigurationException
{
- return getIndexDir();
+ return new File(getIndexDirParam());
}
/**
@@ -1265,7 +1252,6 @@
{
try
{
- File indexDir = new File(getIndexDirectory());
File backupDir = new File(storageDir, getStorageName());
if (!PrivilegedFileHelper.exists(backupDir))
@@ -1275,7 +1261,7 @@
}
else
{
- return new DirectoryRestor(indexDir, backupDir);
+ return new DirectoryRestor(getIndexDirectory(), backupDir);
}
}
catch (RepositoryConfigurationException e)
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -28,12 +28,14 @@
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.backup.SuspendException;
+import org.exoplatform.services.jcr.impl.backup.Suspendable;
import org.exoplatform.services.jcr.impl.core.NamespaceRegistryImpl;
import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.rpc.RPCService;
+import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -61,23 +63,22 @@
public static final String INDEX_DIR_SUFFIX = "system";
- public SystemSearchManager(WorkspaceEntry wsConfig, RepositoryEntry rEntry, RepositoryService rService,
+ public SystemSearchManager(WorkspaceEntry wEntry, RepositoryEntry rEntry, RepositoryService rService,
QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
WorkspacePersistentDataManager itemMgr, DocumentReaderService service, ConfigurationManager cfm,
- RepositoryIndexSearcherHolder indexSearcherHolder) throws RepositoryException, RepositoryConfigurationException
+ RepositoryIndexSearcherHolder indexSearcherHolder, RPCService rpcService) throws RepositoryException,
+ RepositoryConfigurationException
{
- super(wsConfig, rEntry, rService, config, nsReg, ntReg, itemMgr, null, service, cfm, indexSearcherHolder);
+ super(wEntry, rEntry, rService, config, nsReg, ntReg, itemMgr, null, service, cfm, indexSearcherHolder,
+ rpcService);
}
- public SystemSearchManager(WorkspaceEntry wsConfig, RepositoryEntry rEntry, RepositoryService rService,
+ public SystemSearchManager(WorkspaceEntry wEntry, RepositoryEntry rEntry, RepositoryService rService,
QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
- WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
- DocumentReaderService extractor, ConfigurationManager cfm,
- final RepositoryIndexSearcherHolder indexSearcherHolder, RPCService rpcService) throws RepositoryException,
- RepositoryConfigurationException
+ WorkspacePersistentDataManager itemMgr, DocumentReaderService service, ConfigurationManager cfm,
+ RepositoryIndexSearcherHolder indexSearcherHolder) throws RepositoryException, RepositoryConfigurationException
{
- super(wsConfig, rEntry, rService, config, nsReg, ntReg, itemMgr, null, extractor, cfm, indexSearcherHolder,
- rpcService);
+ this(wEntry, rEntry, rService, config, nsReg, ntReg, itemMgr, service, cfm, indexSearcherHolder, null);
}
@Override
@@ -97,9 +98,7 @@
indexingTree = new IndexingTree(indexingRootNodeData, excludedPaths);
}
initializeQueryHandler();
-
}
-
catch (RepositoryException e)
{
log.error(e.getLocalizedMessage());
@@ -122,9 +121,9 @@
* {@inheritDoc}
*/
@Override
- protected String getIndexDirectory() throws RepositoryConfigurationException
+ protected File getIndexDirectory() throws RepositoryConfigurationException
{
- return getIndexDir() + "_" + INDEX_DIR_SUFFIX;
+ return new File(getIndexDirParam() + "_" + INDEX_DIR_SUFFIX);
}
/**
@@ -139,6 +138,11 @@
@Override
protected void suspendLocally() throws SuspendException
{
+ if (isResponsibleForResuming && suspendFlag == Suspendable.SUSPEND_COMPONENT_ON_OTHERS_NODES_ONLY)
+ {
+ return;
+ }
+
super.suspendLocally();
isStarted = false;
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -21,12 +21,16 @@
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.store.Directory;
+import org.exoplatform.commons.utils.PrivilegedFileHelper;
import org.exoplatform.commons.utils.SecurityHelper;
import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.datamodel.NodeDataIndexing;
import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.backup.ResumeException;
+import org.exoplatform.services.jcr.impl.backup.SuspendException;
+import org.exoplatform.services.jcr.impl.backup.Suspendable;
import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeHandler;
import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeListener;
@@ -37,8 +41,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
@@ -430,31 +437,44 @@
reindexing = true;
try
{
- // traverse and index workspace
- executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
+ if (handler.getIndexRecoveryMode().equals(SearchIndex.INDEX_RECOVERY_MODE_FROM_COORDINATOR)
+ && handler.getContext().getIndexRetrieve() != null)
+ {
+ log.info("Retrieving index from coordinator...");
+ retreiveIndexFromCoordinator();
- long count;
-
- // check if we have deal with RDBMS reindexing mechanism
- Reindexable rdbmsReindexableComponent =
- (Reindexable)handler.getContext().getContainer().getComponent(Reindexable.class);
-
- if (handler.isRDBMSReindexing() && rdbmsReindexableComponent != null
- && rdbmsReindexableComponent.isReindexingSupport())
- {
- count =
- createIndex(rdbmsReindexableComponent.getNodeDataIndexingIterator(handler.getReindexingPageSize()),
- indexingTree.getIndexingRoot());
+ indexNames.read();
+ refreshIndexList();
}
else
{
- count = createIndex(indexingTree.getIndexingRoot(), stateMgr);
+ // traverse and index workspace
+ executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
+
+ long count;
+
+ // check if we have deal with RDBMS reindexing mechanism
+ Reindexable rdbmsReindexableComponent =
+ (Reindexable)handler.getContext().getContainer().getComponent(Reindexable.class);
+
+ if (handler.isRDBMSReindexing() && rdbmsReindexableComponent != null
+ && rdbmsReindexableComponent.isReindexingSupport())
+ {
+ count =
+ createIndex(
+ rdbmsReindexableComponent.getNodeDataIndexingIterator(handler.getReindexingPageSize()),
+ indexingTree.getIndexingRoot());
+ }
+ else
+ {
+ count = createIndex(indexingTree.getIndexingRoot(), stateMgr);
+ }
+
+ executeAndLog(new Commit(getTransactionId()));
+ log.info("Created initial index for {} nodes", new Long(count));
+ releaseMultiReader();
+ scheduleFlushTask();
}
-
- executeAndLog(new Commit(getTransactionId()));
- log.info("Created initial index for {} nodes", new Long(count));
- releaseMultiReader();
- scheduleFlushTask();
}
catch (Exception e)
{
@@ -3318,4 +3338,82 @@
}
}
}
+
+ /**
+ * Retrieve index from other node.
+ *
+ * @throws SuspendException
+ * @throws IOException.
+ * @throws RepositoryException.
+ * @throws FileNotFoundException.
+ */
+ private void retreiveIndexFromCoordinator() throws FileNotFoundException, RepositoryException, IOException,
+ SuspendException
+ {
+ List<Suspendable> suspendableComponents =
+ handler.getContext().getContainer().getComponentInstancesOfType(Suspendable.class);
+
+ // the list of components to resume
+ List<Suspendable> resumeComponents = new ArrayList<Suspendable>();
+
+ try
+ {
+ // suspend all components
+ for (Suspendable component : suspendableComponents)
+ {
+ component.suspend(Suspendable.SUSPEND_COMPONENT_ON_OTHERS_NODES_ONLY);
+ resumeComponents.add(component);
+ }
+
+ File indexDirectory = new File(handler.getContext().getIndexDirectory());
+ for (String filePath : handler.getContext().getIndexRetrieve().getIndexList())
+ {
+ File indexFile = new File(indexDirectory, filePath);
+ if (!PrivilegedFileHelper.exists(indexFile.getParentFile()))
+ {
+ PrivilegedFileHelper.mkdirs(indexFile.getParentFile());
+ }
+
+ // transfer file
+ InputStream in = handler.getContext().getIndexRetrieve().getIndexFile(filePath);
+ OutputStream out = PrivilegedFileHelper.fileOutputStream(indexFile);
+ try
+ {
+ byte[] buf = new byte[2048];
+ int len;
+
+ while ((len = in.read(buf)) > 0)
+ {
+ out.write(buf, 0, len);
+ }
+ }
+ finally
+ {
+ if (in != null)
+ {
+ in.close();
+ }
+
+ if (out != null)
+ {
+ out.close();
+ }
+ }
+ }
+ }
+ finally
+ {
+ for (Suspendable component : resumeComponents)
+ {
+ try
+ {
+ component.resume();
+ }
+ catch (ResumeException e)
+ {
+ log.error("Can't resume component", e);
+ }
+ }
+ }
+ }
}
\ No newline at end of file
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -180,6 +180,16 @@
*/
public static final boolean DEFAULT_RDBMS_REINDEXING = true;
+ /**
+ * The default value for {@link #indexRecoveryMode}.
+ */
+ public static final String INDEX_RECOVERY_MODE_FROM_INDEXING = "from-indexing";
+
+ /**
+ * The alternative value for {@link #indexRecoveryMode}.
+ */
+ public static final String INDEX_RECOVERY_MODE_FROM_COORDINATOR = "from-coordinator";
+
/**
* Default name of the error log file
*/
@@ -475,6 +485,11 @@
*/
private boolean rdbmsReindexing = DEFAULT_RDBMS_REINDEXING;
+ /**
+ * The way to create initial index..
+ */
+ private String indexRecoveryMode = INDEX_RECOVERY_MODE_FROM_INDEXING;
+
/**
* Working constructor.
*
@@ -2709,6 +2724,14 @@
return rdbmsReindexing;
}
+ /**
+ * @return the current value for indexRecoveryMode
+ */
+ public String getIndexRecoveryMode()
+ {
+ return indexRecoveryMode;
+ }
+
/**
* Sets a new value for termInfosIndexDivisor.
*
@@ -2763,6 +2786,17 @@
this.rdbmsReindexing = rdbmsReindexing;
}
+ /**
+ * Set a new value for indexRecoveryMode.
+ *
+ * @param indexRecoveryMode
+ * the new value for indexRecoveryMode
+ */
+ public void setIndexRecoveryMode(String indexRecoveryMode)
+ {
+ this.indexRecoveryMode = indexRecoveryMode;
+ }
+
// ----------------------------< internal
// >----------------------------------
@@ -2898,7 +2932,7 @@
if (mode == IndexerIoMode.READ_WRITE)
{
// reprocess any notfinished notifies;
- log.info("Proceessing eroor log ...");
+ log.info("Proceessing error log ...");
recoverErrorLog(errorLog);
}
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -122,6 +122,11 @@
private RemoteCommand resume;
/**
+ * Suspend flag.
+ */
+ private Integer suspendFlag;
+
+ /**
* ItemData request, used on get operations.
*
*/
@@ -1095,9 +1100,10 @@
/**
* {@inheritDoc}
*/
- public void suspend() throws SuspendException
+ public void suspend(int flag) throws SuspendException
{
isResponsibleForResuming = true;
+ suspendFlag = flag;
if (rpcService != null)
{
@@ -1146,10 +1152,16 @@
}
isResponsibleForResuming = false;
+ suspendFlag = null;
}
private void suspendLocally() throws SuspendException
{
+ if (isResponsibleForResuming && suspendFlag == Suspendable.SUSPEND_COMPONENT_ON_OTHERS_NODES_ONLY)
+ {
+ return;
+ }
+
if (isSuspended)
{
throw new SuspendException("Component already suspended.");
@@ -1173,6 +1185,11 @@
private void resumeLocally() throws ResumeException
{
+ if (isResponsibleForResuming && suspendFlag == Suspendable.SUSPEND_COMPONENT_ON_OTHERS_NODES_ONLY)
+ {
+ return;
+ }
+
if (!isSuspended)
{
throw new ResumeException("Component is not suspended.");
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/io/DirectoryHelper.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/io/DirectoryHelper.java 2011-02-16 10:02:16 UTC (rev 3980)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/io/DirectoryHelper.java 2011-02-17 13:57:37 UTC (rev 3981)
@@ -24,6 +24,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -42,6 +44,36 @@
{
/**
+ * Returns the files list of whole directory including its sub directories.
+ *
+ * @param srcPath
+ * source path
+ * @return List
+ * @throws IOException
+ * if any exception occurred
+ */
+ public static List<File> listFiles(File srcPath) throws IOException
+ {
+ List<File> result = new ArrayList<File>();
+
+ if (!PrivilegedFileHelper.isDirectory(srcPath))
+ {
+ throw new IOException(PrivilegedFileHelper.getAbsolutePath(srcPath) + " is a directory");
+ }
+
+ for (File subFile : PrivilegedFileHelper.listFiles(srcPath))
+ {
+ result.add(subFile);
+ if (subFile.isDirectory())
+ {
+ result.addAll(listFiles(subFile));
+ }
+ }
+
+ return result;
+ }
+
+ /**
* Copy directory.
*
* @param srcPath
13 years, 3 months
exo-jcr SVN: r3980 - in jcr/trunk/exo.jcr.component.core/src: main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache and 3 other directories.
by do-not-reply@jboss.org
Author: nzamosenchuk
Date: 2011-02-16 05:02:16 -0500 (Wed, 16 Feb 2011)
New Revision: 3980
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexCacheLoader.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexChangesFilter.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/ChangesHolder.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/query/lucene/TestChangesHolder.java
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JBossCacheIndexChangesFilter.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SingletonTokenStream.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java
Log:
EXOJCR-1080 : Merging work done in IMPR branch back to trunk. This contains:
a) Each cluster node has it's own volatile index
b) Lucene Documents are replicated via cluster instead of UUIDs
c) Set of classes for LocalIndexes on each cluster node (LocalIndexChangesFilter, LocalIndexCacheLoader).
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -109,9 +109,6 @@
*/
public void onSaveItems(ItemStateChangesLog itemStates)
{
-
- long time = System.currentTimeMillis();
-
// nodes that need to be removed from the index.
final Set<String> removedNodes = new HashSet<String>();
// nodes that need to be added to the index.
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -21,6 +21,7 @@
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.impl.core.SessionDataManager;
import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
import org.exoplatform.services.jcr.impl.core.query.lucene.IndexUpdateMonitor;
import org.exoplatform.services.jcr.impl.core.query.lucene.MultiIndex;
@@ -79,6 +80,23 @@
void updateNodes(Iterator<String> remove, Iterator<NodeData> add) throws RepositoryException, IOException;
/**
+ * Extracts all the changes and returns them as a {@link ChangesHolder} instance
+ * @param remove Iterator of <code>NodeIds</code> of nodes to delete
+ * @param add Iterator of <code>NodeState</code> instance to add to the
+ * index.
+ * @return a {@link ChangesHolder} instance that contains all the changes
+ */
+ ChangesHolder getChanges(Iterator<String> remove, Iterator<NodeData> add);
+
+ /**
+ * Applies the given changes to the indes in an atomic operation
+ * @param changes the changes to apply
+ * @throws RepositoryException if an error occurs while indexing a node.
+ * @throws IOException if an error occurs while updating the index.
+ */
+ void apply(ChangesHolder changes) throws RepositoryException, IOException;
+
+ /**
* Closes this <code>QueryHandler</code> and frees resources attached
* to this handler.
*/
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -54,6 +54,7 @@
import org.exoplatform.services.jcr.impl.core.NamespaceRegistryImpl;
import org.exoplatform.services.jcr.impl.core.SessionDataManager;
import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
import org.exoplatform.services.jcr.impl.core.query.lucene.FieldNames;
import org.exoplatform.services.jcr.impl.core.query.lucene.LuceneVirtualTableResolver;
import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
@@ -600,6 +601,23 @@
public void updateIndex(final Set<String> removedNodes, final Set<String> addedNodes) throws RepositoryException,
IOException
{
+ final ChangesHolder changes = getChanges(removedNodes, addedNodes);
+ apply(changes);
+ }
+
+ public void apply(ChangesHolder changes) throws RepositoryException, IOException
+ {
+ if (handler != null && changes != null && (!changes.getAdd().isEmpty() || !changes.getRemove().isEmpty()))
+ {
+ handler.apply(changes);
+ }
+ }
+
+ /**
+ * Extracts all the changes and returns them as a {@link ChangesHolder} instance
+ */
+ public ChangesHolder getChanges(final Set<String> removedNodes, final Set<String> addedNodes)
+ {
if (handler != null)
{
Iterator<NodeData> addedStates = new Iterator<NodeData>()
@@ -680,12 +698,12 @@
if (removedNodes.size() > 0 || addedNodes.size() > 0)
{
- handler.updateNodes(removedIds, addedStates);
+ return handler.getChanges(removedIds, addedStates);
}
}
-
+ return null;
}
-
+
protected QueryHandlerContext createQueryHandlerContext(QueryHandler parentHandler)
throws RepositoryConfigurationException
{
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -18,6 +18,8 @@
*/
package org.exoplatform.services.jcr.impl.core.query.jbosscache;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
+
import java.io.Serializable;
import java.util.Set;
@@ -40,6 +42,10 @@
private Set<String> parentRemovedNodes;
+ private ChangesHolder changes;
+
+ private ChangesHolder parentChanges;
+
/**
* Creates ChangesFilterListsWrapper data class, containing given lists.
*
@@ -56,7 +62,31 @@
this.parentAddedNodes = parentAddedNodes;
this.parentRemovedNodes = parentRemovedNodes;
}
+
+ /**
+ * Creates ChangesFilterListsWrapper data class, containing given lists.
+ */
+ public ChangesFilterListsWrapper(ChangesHolder changes, ChangesHolder parentChanges)
+ {
+ this.changes = changes;
+ this.parentChanges = parentChanges;
+ }
+ public boolean withChanges()
+ {
+ return changes != null || parentChanges != null;
+ }
+
+ public ChangesHolder getChanges()
+ {
+ return changes;
+ }
+
+ public ChangesHolder getParentChanges()
+ {
+ return parentChanges;
+ }
+
public Set<String> getAddedNodes()
{
return addedNodes;
@@ -76,15 +106,4 @@
{
return parentRemovedNodes;
}
-
- public String dump()
- {
- StringBuffer buffer = new StringBuffer();
- buffer.append("\n");
- buffer.append("Added=").append(addedNodes.toString()).append("\n");
- buffer.append("Removed=").append(removedNodes.toString()).append("\n");
- buffer.append("ParentAdded=").append(parentAddedNodes.toString()).append("\n");
- buffer.append("ParentRemoved=").append(parentRemovedNodes.toString());
- return buffer.toString();
- }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -21,6 +21,7 @@
import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeHandler;
import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
import org.exoplatform.services.jcr.impl.core.query.SearchManager;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
import org.exoplatform.services.jcr.impl.storage.jbosscache.AbstractWriteOnlyCacheLoader;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
@@ -30,6 +31,7 @@
import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -50,7 +52,7 @@
*/
private final Map<Fqn<String>, Indexer> indexers = new HashMap<Fqn<String>, Indexer>();
- private volatile IndexerIoModeHandler modeHandler;
+ protected volatile IndexerIoModeHandler modeHandler;
/**
* @see org.jboss.cache.loader.AbstractCacheLoader#commit(java.lang.Object)
@@ -60,7 +62,7 @@
{
// do nothing. Everything is done on prepare phase.
}
-
+
/**
* This method will register a new Indexer according to the given parameters.
*
@@ -75,7 +77,10 @@
{
indexers.put(Fqn.fromElements(searchManager.getWsId()), new Indexer(searchManager, parentSearchManager, handler,
parentHandler));
- if (log.isDebugEnabled()) log.debug("Register " + searchManager.getWsId() + " " + this + " in " + indexers);
+ if (log.isDebugEnabled())
+ {
+ log.debug("Register " + searchManager.getWsId() + " " + this + " in " + indexers);
+ }
}
/**
@@ -97,18 +102,28 @@
if (indexer == null)
{
log.warn("No indexer could be found for the fqn " + name.getParent());
- if (log.isDebugEnabled()) log.debug("The current content of the map of indexers is " + indexers);
+ if (log.isDebugEnabled())
+ {
+ log.debug("The current content of the map of indexers is " + indexers);
+ }
}
+ else if (wrapper.withChanges())
+ {
+ indexer.updateIndex(wrapper.getChanges(), wrapper.getParentChanges());
+ }
else
{
- indexer.updateIndex(wrapper.getAddedNodes(), wrapper.getRemovedNodes(), wrapper.getParentAddedNodes(), wrapper
- .getParentRemovedNodes());
+ indexer.updateIndex(wrapper.getAddedNodes(), wrapper.getRemovedNodes(), wrapper.getParentAddedNodes(),
+ wrapper.getParentRemovedNodes());
}
}
finally
{
- // remove the data from the cache
- cache.removeNode(name);
+ if (modeHandler.getMode() == IndexerIoMode.READ_WRITE)
+ {
+ // remove the data from the cache
+ cache.removeNode(name);
+ }
}
}
return null;
@@ -190,7 +205,7 @@
private final QueryHandler handler;
private final QueryHandler parentHandler;
-
+
public Indexer(SearchManager searchManager, SearchManager parentSearchManager, QueryHandler handler,
QueryHandler parentHandler) throws RepositoryConfigurationException
{
@@ -198,7 +213,8 @@
this.parentSearchManager = parentSearchManager;
this.handler = handler;
this.parentHandler = parentHandler;
- }
+ }
+
/**
* Flushes lists of added/removed nodes to SearchManagers, starting indexing.
*
@@ -250,7 +266,7 @@
log.error("Error indexing changes " + e, e);
try
{
- parentHandler.logErrorChanges(removedNodes, addedNodes);
+ parentHandler.logErrorChanges(parentRemovedNodes, parentAddedNodes);
}
catch (IOException ioe)
{
@@ -258,6 +274,63 @@
}
}
}
- }
+ }
+
+ /**
+ * Flushes lists of added/removed nodes to SearchManagers, starting indexing.
+ */
+ protected void updateIndex(ChangesHolder changes, ChangesHolder parentChanges)
+ {
+ // pass lists to search manager
+ if (searchManager != null && changes != null)
+ {
+ try
+ {
+ searchManager.apply(changes);
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ }
+ catch (IOException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ try
+ {
+ handler.logErrorChanges(new HashSet<String>(changes.getRemove()), new HashSet<String>(changes
+ .getAddIds()));
+ }
+ catch (IOException ioe)
+ {
+ log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
+ }
+ }
+ }
+ // pass lists to parent search manager
+ if (parentSearchManager != null && parentChanges != null)
+ {
+ try
+ {
+ parentSearchManager.apply(parentChanges);
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ }
+ catch (IOException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ try
+ {
+ parentHandler.logErrorChanges(new HashSet<String>(parentChanges.getRemove()), new HashSet<String>(
+ parentChanges.getAddIds()));
+ }
+ catch (IOException ioe)
+ {
+ log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
+ }
+ }
+ }
+ }
}
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -79,28 +79,46 @@
{
Fqn<?> fqn = aChildren.getFqn();
Object value = cache.get(fqn, JBossCacheIndexChangesFilter.LISTWRAPPER);
- if (value != null && value instanceof ChangesFilterListsWrapper)
+ if (value instanceof ChangesFilterListsWrapper)
{
// get wrapper object
ChangesFilterListsWrapper listsWrapper = (ChangesFilterListsWrapper)value;
- // get search manager lists
- addedNodes.addAll(listsWrapper.getAddedNodes());
- removedNodes.addAll(listsWrapper.getRemovedNodes());
- // parent search manager lists
- parentAddedNodes.addAll(listsWrapper.getParentAddedNodes());
- parentRemovedNodes.addAll(listsWrapper.getParentAddedNodes());
- }
+ if (listsWrapper.withChanges())
+ {
+ if (listsWrapper.getChanges() != null)
+ {
+ // get search manager lists
+ addedNodes.addAll(listsWrapper.getChanges().getAddIds());
+ removedNodes.addAll(listsWrapper.getChanges().getRemove());
+ }
+ if (listsWrapper.getParentChanges() != null)
+ {
+ // parent search manager lists
+ parentAddedNodes.addAll(listsWrapper.getParentChanges().getAddIds());
+ parentRemovedNodes.addAll(listsWrapper.getParentChanges().getRemove());
+ }
+ }
+ else
+ {
+ // get search manager lists
+ addedNodes.addAll(listsWrapper.getAddedNodes());
+ removedNodes.addAll(listsWrapper.getRemovedNodes());
+ // parent search manager lists
+ parentAddedNodes.addAll(listsWrapper.getParentAddedNodes());
+ parentRemovedNodes.addAll(listsWrapper.getParentAddedNodes());
+ }
+ }
}
String id = IdGenerator.generate();
- cache.put(Fqn.fromRelativeElements(wsChildren.getFqn(), id), JBossCacheIndexChangesFilter.LISTWRAPPER, new ChangesFilterListsWrapper(addedNodes,
- removedNodes, parentAddedNodes, parentRemovedNodes));
+ cache.put(Fqn.fromRelativeElements(wsChildren.getFqn(), id), JBossCacheIndexChangesFilter.LISTWRAPPER,
+ new ChangesFilterListsWrapper(addedNodes, removedNodes, parentAddedNodes, parentRemovedNodes));
// Once we put the merged changes into the cache we can remove other changes from the cache
- for (NodeSPI aChildren : children)
- {
+ for (NodeSPI aChildren : children)
+ {
// Remove the node from the cache and do it asynchronously
- cache.getInvocationContext().getOptionOverrides().setForceAsynchronous(true);
- cache.removeNode(aChildren.getFqn());
- }
+ cache.getInvocationContext().getOptionOverrides().setForceAsynchronous(true);
+ cache.removeNode(aChildren.getFqn());
+ }
}
if (debugEnabled)
{
@@ -111,6 +129,15 @@
};
}
+ @Override
+ public Object put(Fqn name, Object key, Object value) throws Exception
+ {
+ // delegating call to underlying cache loader, skipping SingletonStore cache loader.
+ // this is used to deliver lists to non-coordinator nodes, since the do the indexing into
+ // volatile index
+ return getCacheLoader().put(name, key, value);
+ }
+
/**
* Sets/changes indexer mode
*
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JBossCacheIndexChangesFilter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JBossCacheIndexChangesFilter.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JBossCacheIndexChangesFilter.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -27,6 +27,7 @@
import org.exoplatform.services.jcr.impl.core.query.IndexingTree;
import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
import org.exoplatform.services.jcr.impl.core.query.SearchManager;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory;
import org.exoplatform.services.jcr.jbosscache.PrivilegedJBossCacheHelper;
import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory.CacheType;
@@ -189,11 +190,18 @@
protected void doUpdateIndex(Set<String> removedNodes, Set<String> addedNodes, Set<String> parentRemovedNodes,
Set<String> parentAddedNodes)
{
+ ChangesHolder changes = searchManager.getChanges(removedNodes, addedNodes);
+ ChangesHolder parentChanges = parentSearchManager.getChanges(parentRemovedNodes, parentAddedNodes);
+
+ if (changes == null && parentChanges == null)
+ {
+ return;
+ }
String id = IdGenerator.generate();
try
{
PrivilegedJBossCacheHelper.put(cache, Fqn.fromRelativeElements(rootFqn, id), LISTWRAPPER,
- new ChangesFilterListsWrapper(addedNodes, removedNodes, parentAddedNodes, parentRemovedNodes));
+ new ChangesFilterListsWrapper(changes, parentChanges));
}
catch (CacheException e)
{
Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexCacheLoader.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexCacheLoader.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexCacheLoader.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.core.query.jbosscache;
+
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeHandler;
+
+/**
+ * This cache loader replaces Indexer IO Mode handling with constant ReadWrite state.
+ * This is required for indexing in cluster, when each instance has it's own index stack,
+ * having local FileSystem with LuceneDirectories.
+ *
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: LocalIndexCacheLoader.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class LocalIndexCacheLoader extends IndexerCacheLoader
+{
+ public LocalIndexCacheLoader()
+ {
+ super();
+ modeHandler = new IndexerIoModeHandler(IndexerIoMode.READ_WRITE); // initialize mode handler
+ }
+
+ @Override
+ IndexerIoModeHandler getModeHandler()
+ {
+ return modeHandler;
+ }
+
+ @Override
+ void setMode(IndexerIoMode ioMode)
+ {
+ // can't set RO on this cache loader
+ if (ioMode == IndexerIoMode.READ_ONLY)
+ {
+ throw new UnsupportedOperationException(
+ "Can't set ReadOnly on this type of CacheLoader. It is designed to provide local index for each cluster instance. Make sure you are using Index properly.");
+ }
+ }
+
+}
Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexChangesFilter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexChangesFilter.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/LocalIndexChangesFilter.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.core.query.jbosscache;
+
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.services.jcr.config.QueryHandlerEntry;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.impl.core.query.IndexerChangesFilter;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeHandler;
+import org.exoplatform.services.jcr.impl.core.query.IndexingTree;
+import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
+import org.exoplatform.services.jcr.impl.core.query.SearchManager;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
+import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory;
+import org.exoplatform.services.jcr.jbosscache.PrivilegedJBossCacheHelper;
+import org.exoplatform.services.jcr.jbosscache.ExoJBossCacheFactory.CacheType;
+import org.exoplatform.services.jcr.util.IdGenerator;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.jboss.cache.Cache;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.CacheLoaderConfig;
+import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * This type of ChangeFilter offers an ability for each cluster instance to have own
+ * local index (stack of indexes, from persistent to volatile). It uses JBossCache for
+ * Lucene Documents and UUIDs delivery. Each node works in ReadWrite mode, so manages
+ * it own volatile, merger, local list of persisted indexes and stand-alone
+ * UpdateInProgressMonitor implementation.
+ * This implementation is similar to JBossCacheIndexChangesFilter but it doesn't use
+ * SingletonStoreCacheLoader tier and cluster-aware implementations of IndexInfos
+ * and UpdateInProgressMonitor.
+ *
+ * @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $
+ *
+ */
+public class LocalIndexChangesFilter extends IndexerChangesFilter
+{
+ /**
+ * Logger instance for this class
+ */
+ private final Log log = ExoLogger.getLogger("exo.jcr.component.core.JBossCacheIndexChangesFilter");
+
+ public static final String PARAM_JBOSSCACHE_CONFIGURATION = "jbosscache-configuration";
+
+ public static final String PARAM_JBOSSCACHE_PUSHSTATE = "jbosscache-sscl-push.state.enabled";
+
+ public static final String PARAM_JBOSSCACHE_PUSHSTATE_TIMEOUT = "jbosscache-sscl-push.state.timeout";
+
+ /**
+ * Indicate whether the JBoss Cache instance used can be shared with other caches
+ */
+ public static final String PARAM_JBOSSCACHE_SHAREABLE = "jbosscache-shareable";
+
+ public static final Boolean PARAM_JBOSSCACHE_SHAREABLE_DEFAULT = Boolean.FALSE;
+
+ private final Cache<Serializable, Object> cache;
+
+ private final Fqn<String> rootFqn;
+
+ public static final String LISTWRAPPER = "$lists".intern();
+
+ /**
+ * @param searchManager
+ * @param config
+ * @param indexingTree
+ * @throws RepositoryConfigurationException
+ */
+ public LocalIndexChangesFilter(SearchManager searchManager, SearchManager parentSearchManager,
+ QueryHandlerEntry config, IndexingTree indexingTree, IndexingTree parentIndexingTree, QueryHandler handler,
+ QueryHandler parentHandler, ConfigurationManager cfm) throws IOException, RepositoryException,
+ RepositoryConfigurationException
+ {
+ super(searchManager, parentSearchManager, config, indexingTree, parentIndexingTree, handler, parentHandler, cfm);
+ // create cache using custom factory
+ ExoJBossCacheFactory<Serializable, Object> factory = new ExoJBossCacheFactory<Serializable, Object>(cfm);
+ Cache<Serializable, Object> initCache = factory.createCache(config);
+
+ // initialize IndexerCacheLoader
+ IndexerCacheLoader indexerCacheLoader = new LocalIndexCacheLoader();
+
+ // create CacheLoaderConfig
+ IndividualCacheLoaderConfig individualCacheLoaderConfig = new IndividualCacheLoaderConfig();
+ // set CacheLoader
+ individualCacheLoaderConfig.setCacheLoader(indexerCacheLoader);
+ // set parameters
+ individualCacheLoaderConfig.setFetchPersistentState(false);
+ individualCacheLoaderConfig.setAsync(false);
+ individualCacheLoaderConfig.setIgnoreModifications(false);
+ individualCacheLoaderConfig.setPurgeOnStartup(false);
+ // create CacheLoaderConfig
+ CacheLoaderConfig cacheLoaderConfig = new CacheLoaderConfig();
+ cacheLoaderConfig.setShared(false);
+ cacheLoaderConfig.setPassivation(false);
+ cacheLoaderConfig.addIndividualCacheLoaderConfig(individualCacheLoaderConfig);
+ // insert CacheLoaderConfig
+ initCache.getConfiguration().setCacheLoaderConfig(cacheLoaderConfig);
+ this.rootFqn = Fqn.fromElements(searchManager.getWsId());
+ this.cache =
+ ExoJBossCacheFactory.getUniqueInstance(CacheType.INDEX_CACHE, rootFqn, initCache, config.getParameterBoolean(
+ PARAM_JBOSSCACHE_SHAREABLE, PARAM_JBOSSCACHE_SHAREABLE_DEFAULT));
+
+ PrivilegedJBossCacheHelper.create(cache);
+ PrivilegedJBossCacheHelper.start(cache);
+
+ indexerCacheLoader = (IndexerCacheLoader)((CacheSPI)cache).getCacheLoaderManager().getCacheLoader();
+
+ indexerCacheLoader.register(searchManager, parentSearchManager, handler, parentHandler);
+ IndexerIoModeHandler modeHandler = indexerCacheLoader.getModeHandler();
+ handler.setIndexerIoModeHandler(modeHandler);
+ parentHandler.setIndexerIoModeHandler(modeHandler);
+
+ // using default updateMonitor and default
+ if (!parentHandler.isInitialized())
+ {
+ parentHandler.init();
+ }
+ if (!handler.isInitialized())
+ {
+ handler.init();
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.impl.core.query.IndexerChangesFilter#doUpdateIndex(java.util.Set, java.util.Set, java.util.Set, java.util.Set)
+ */
+ @Override
+ protected void doUpdateIndex(Set<String> removedNodes, Set<String> addedNodes, Set<String> parentRemovedNodes,
+ Set<String> parentAddedNodes)
+ {
+
+ ChangesHolder changes = searchManager.getChanges(removedNodes, addedNodes);
+ ChangesHolder parentChanges = parentSearchManager.getChanges(parentRemovedNodes, parentAddedNodes);
+
+ if (changes == null && parentChanges == null)
+ {
+ return;
+ }
+ String id = IdGenerator.generate();
+ try
+ {
+ PrivilegedJBossCacheHelper.put(cache, Fqn.fromRelativeElements(rootFqn, id), LISTWRAPPER,
+ new ChangesFilterListsWrapper(changes, parentChanges));
+ }
+ catch (CacheException e)
+ {
+ log.error(e.getLocalizedMessage(), e);
+ logErrorChanges(handler, removedNodes, addedNodes);
+ logErrorChanges(parentHandler, parentRemovedNodes, parentAddedNodes);
+ }
+ }
+
+ /**
+ * Log errors
+ * @param logHandler
+ * @param removedNodes
+ * @param addedNodes
+ */
+ private void logErrorChanges(QueryHandler logHandler, Set<String> removedNodes, Set<String> addedNodes)
+ {
+ try
+ {
+ logHandler.logErrorChanges(addedNodes, removedNodes);
+ }
+ catch (IOException ioe)
+ {
+ log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
+ }
+ }
+}
Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/ChangesHolder.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/ChangesHolder.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/ChangesHolder.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.core.query.lucene;
+
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Fieldable;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class is used to serialize and deserialize the changes to apply to the lucene index.
+ *
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public class ChangesHolder implements Externalizable
+{
+
+ private static final int STORED_FLAG = 1;
+
+ private static final int COMPRESSED_FLAG = 1 << 1;
+
+ private static final int INDEXED_FLAG = 1 << 2;
+
+ private static final int TOKENIZED_FLAG = 1 << 3;
+
+ private static final int OMIT_NORMS_FLAG = 1 << 4;
+
+ private static final int BINARY_FLAG = 1 << 5;
+
+ private static final int STORE_TERM_VECTOR_FLAG = 1 << 6;
+
+ private static final int STORE_POSITION_WITH_TERM_VECTOR_FLAG = 1 << 7;
+
+ private static final int STORE_OFFSET_WITH_TERM_VECTOR_FLAG = 1 << 8;
+
+ private static final int LAZY_FLAG = 1 << 9;
+
+ private static final int OMIT_TF_FLAG = 1 << 10;
+
+ private static final int BOOST_FLAG = 1 << 11;
+
+ /**
+ * List of doc ids to remove from the index
+ */
+ private List<String> remove;
+
+ /**
+ * Collection of Lucene Documents to add to the index
+ */
+ private Collection<Document> add;
+
+ /**
+ * Default constructor used during the deserializing phase
+ */
+ public ChangesHolder()
+ {
+ }
+
+ /**
+ * @param remove Collection of doc ids to remove from the index
+ * @param add Lucene Documents to add to the index
+ */
+ public ChangesHolder(Collection<String> remove, Collection<Document> add)
+ {
+ this.remove = new ArrayList<String>(remove);
+ this.add = add;
+ }
+
+ /**
+ * @return the collection of doc id to remove
+ */
+ public Collection<String> getRemove()
+ {
+ return remove;
+ }
+
+ /**
+ * @return the collection of lucene document to add
+ */
+ public Collection<Document> getAdd()
+ {
+ return add;
+ }
+
+ /**
+ * @return the collection of id of lucene document to add
+ */
+ public Collection<String> getAddIds()
+ {
+ Collection<String> ids = new LinkedList<String>();
+ for (Document doc : add)
+ {
+ ids.add(getDocId(doc));
+ }
+ return ids;
+ }
+
+ /**
+ * @return the id of the given lucene doc
+ */
+ public String getDocId(Document doc)
+ {
+ return doc.get(FieldNames.UUID);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ int length = in.readInt();
+ this.remove = new ArrayList<String>(length);
+ for (int i = 0; i < length; i++)
+ {
+ remove.add(in.readUTF());
+ }
+ this.add = new LinkedList<Document>();
+ while (in.readBoolean())
+ {
+ Document doc = new Document();
+ doc.setBoost(in.readFloat());
+ int l = in.readInt();
+ for (int i = 0; i < l; i++)
+ {
+ doc.add(readField(in, doc));
+ }
+ add.add(doc);
+ }
+ }
+
+ /**
+ * Deserialize the field from the given {@link ObjectInput}
+ * @param in the stream from which we deserialize the Field
+ * @return the deserialized field
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ private static Field readField(ObjectInput in, Document doc) throws IOException, ClassNotFoundException
+ {
+ String name = in.readUTF();
+ int flags = in.readInt();
+ float boost = (flags & BOOST_FLAG) > 0 ? in.readFloat() : 1.0f;
+ Object value = in.readObject();
+ Field field;
+ if (value instanceof TokenStream)
+ {
+ field = new Field(name, (TokenStream)value, getTermVectorParameter(flags));
+ }
+ else
+ {
+ // The value is a String
+ field = new Field(name, (String)value, getStoreParameter(flags), getIndexParameter(flags), getTermVectorParameter(flags));
+ }
+ field.setBoost(boost);
+ field.setOmitNorms((flags & OMIT_NORMS_FLAG) > 0);
+ field.setOmitTf((flags & OMIT_TF_FLAG) > 0);
+ return field;
+ }
+
+ /**
+ * Returns the index parameter extracted from the flags.
+ *
+ * @param flags the flags of the Lucene field.
+ * @return the index parameter corresponding to the given flags.
+ */
+ private static Field.Index getIndexParameter(int flags)
+ {
+ if ((flags & INDEXED_FLAG) == 0)
+ {
+ return Field.Index.NO;
+ }
+ else if ((flags & TOKENIZED_FLAG) > 0)
+ {
+ return Field.Index.ANALYZED;
+ }
+ else
+ {
+ return Field.Index.NOT_ANALYZED;
+ }
+ }
+
+ /**
+ * Returns the store parameter extracted from the flags.
+ *
+ * @param flags the flags of the Lucene field.
+ * @return the store parameter corresponding to the given flags.
+ */
+ private static Field.Store getStoreParameter(int flags)
+ {
+ if ((flags & COMPRESSED_FLAG) > 0)
+ {
+ return Field.Store.COMPRESS;
+ }
+ else if ((flags & STORED_FLAG) > 0)
+ {
+ return Field.Store.YES;
+ }
+ else
+ {
+ return Field.Store.NO;
+ }
+ }
+
+ /**
+ * Returns the term vector parameter extracted from the flags.
+ *
+ * @param flags the flags of the Lucene field.
+ * @return the term vector parameter corresponding to the given flags.
+ */
+ private static Field.TermVector getTermVectorParameter(int flags)
+ {
+ if (((flags & STORE_POSITION_WITH_TERM_VECTOR_FLAG) > 0)
+ && ((flags & STORE_OFFSET_WITH_TERM_VECTOR_FLAG) > 0))
+ {
+ return Field.TermVector.WITH_POSITIONS_OFFSETS;
+ }
+ else if ((flags & STORE_POSITION_WITH_TERM_VECTOR_FLAG) > 0)
+ {
+ return Field.TermVector.WITH_POSITIONS;
+ }
+ else if ((flags & STORE_OFFSET_WITH_TERM_VECTOR_FLAG) > 0)
+ {
+ return Field.TermVector.WITH_OFFSETS;
+ }
+ else if ((flags & STORE_TERM_VECTOR_FLAG) > 0)
+ {
+ return Field.TermVector.YES;
+ }
+ else
+ {
+ return Field.TermVector.NO;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ int length = remove.size();
+ out.writeInt(length);
+ for (int i = 0; i < length; i++)
+ {
+ out.writeUTF(remove.get(i));
+ }
+ out.flush();
+ for (Document doc : add)
+ {
+ // Indicate that there is a doc to come
+ out.writeBoolean(true);
+ // boost
+ out.writeFloat(doc.getBoost());
+ List<Fieldable> fields = doc.getFields();
+ int l = fields.size();
+ out.writeInt(l);
+ for (int i = 0; i < l; i++)
+ {
+ writeField(out, fields.get(i));
+ }
+ out.flush();
+ }
+ // There is no doc anymore
+ out.writeBoolean(false);
+ }
+
+ /**
+ * Serialize the Field into the given {@link ObjectOutput}
+ * @param out the stream in which we serialize the Field
+ * @param field the Field instance to serialize
+ * @throws IOException if the Field could not be serialized
+ */
+ private static void writeField(ObjectOutput out, Fieldable field) throws IOException
+ {
+ // Name
+ out.writeUTF(field.name());
+ // Flags
+ writeFlags(out, field);
+ if (field.getBoost() != 1.0f)
+ {
+ // Boost
+ out.writeFloat(field.getBoost());
+ }
+ // Value
+ writeValue(out, field);
+ }
+
+ /**
+ * Serialize the value into the given {@link ObjectOutput}
+ * @param out the stream in which we serialize the value
+ * @param field the field from which we extract the value
+ * @throws IOException if the value could not be serialized
+ */
+ private static void writeValue(ObjectOutput out, Fieldable field) throws IOException
+ {
+ Object o = field.stringValue();
+ if (o != null)
+ {
+ // Use writeObject instead of writeUTF because the value could contain unsupported
+ // characters
+ out.writeObject(o);
+ return;
+ }
+ o = field.tokenStreamValue();
+ if (o != null)
+ {
+ out.writeObject(o);
+ return;
+ }
+ o = field.readerValue();
+ throw new RuntimeException("Unsupported value " + o);
+ }
+
+ /**
+ * Serialize the flags into the given {@link ObjectOutput}
+ * @param out the stream in which we serialize the flags
+ * @param field the field from which we extract the flags
+ * @throws IOException if the flags could not be serialized
+ */
+ private static void writeFlags(ObjectOutput out, Fieldable field) throws IOException
+ {
+ int flags = 0;
+ if (field.isStored())
+ {
+ flags |= STORED_FLAG;
+ }
+ if (field.isCompressed())
+ {
+ flags |= COMPRESSED_FLAG;
+ }
+ if (field.isIndexed())
+ {
+ flags |= INDEXED_FLAG;
+ }
+ if (field.isTokenized())
+ {
+ flags |= TOKENIZED_FLAG;
+ }
+ if (field.getOmitNorms())
+ {
+ flags |= OMIT_NORMS_FLAG;
+ }
+ if (field.isBinary())
+ {
+ flags |= BINARY_FLAG;
+ }
+ if (field.isTermVectorStored())
+ {
+ flags |= STORE_TERM_VECTOR_FLAG;
+ }
+ if (field.isStorePositionWithTermVector())
+ {
+ flags |= STORE_POSITION_WITH_TERM_VECTOR_FLAG;
+ }
+ if (field.isStoreOffsetWithTermVector())
+ {
+ flags |= STORE_OFFSET_WITH_TERM_VECTOR_FLAG;
+ }
+ if (field.isLazy())
+ {
+ flags |= LAZY_FLAG;
+ }
+ if (field.getOmitTf())
+ {
+ flags |= OMIT_TF_FLAG;
+ }
+ if (field.getBoost() != 1.0f)
+ {
+ flags |= BOOST_FLAG;
+ }
+ out.writeInt(flags);
+ }
+}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -19,6 +19,7 @@
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
import org.apache.lucene.store.Directory;
import org.exoplatform.commons.utils.SecurityHelper;
import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
@@ -489,6 +490,25 @@
*/
synchronized void update(final Collection remove, final Collection add) throws IOException
{
+ if (modeHandler.getMode() == IndexerIoMode.READ_WRITE)
+ {
+ doUpdateRW(remove, add);
+ }
+ else
+ {
+ doUpdateRO(remove, add);
+ }
+ }
+
+ /**
+ * For investigation purposes only
+ *
+ * @param remove
+ * @param add
+ * @throws IOException
+ */
+ private void doUpdateRO(final Collection remove, final Collection add) throws IOException
+ {
SecurityHelper.doPrivilegedIOExceptionAction(new PrivilegedExceptionAction<Object>()
{
public Object run() throws Exception
@@ -506,7 +526,123 @@
log.warn("unable to prepare index reader " + "for queries during update", e);
}
}
+ ReadOnlyIndexReader lastIndexReader = null;
+ try
+ {
+ for (Iterator it = remove.iterator(); it.hasNext();)
+ {
+ Term idTerm = new Term(FieldNames.UUID, (String)it.next());
+ volatileIndex.removeDocument(idTerm);
+ }
+ // try to avoid getting index reader for each doc
+ int lastIndexReaderId = indexes.size() - 1;
+ // check, index list can be empty
+ lastIndexReader =
+ (lastIndexReaderId >= 0) ? ((PersistentIndex)indexes.get(lastIndexReaderId)).getReadOnlyIndexReader()
+ : null;
+ for (Iterator it = add.iterator(); it.hasNext();)
+ {
+ Document doc = (Document)it.next();
+ if (doc != null)
+ {
+ // check if this item should be placed in own volatile index
+ // usually it must be indexed, but exception if it exists in persisted index
+ boolean addDoc = true;
+
+ // make this check safe if something goes wrong
+ String uuid = doc.get(FieldNames.UUID);
+ // if remove contains uuid, node should be re-indexed
+ // if not, than should be checked if node present in the last persisted index
+ if (!remove.contains(uuid))
+ {
+ // if index list changed, get the reader on the latest index
+ // or if index reader is not current
+ if (lastIndexReaderId != indexes.size() - 1
+ || (lastIndexReader != null && !lastIndexReader.isCurrent()))
+ {
+ // safe release reader
+ if (lastIndexReader != null)
+ {
+ lastIndexReader.release();
+ }
+ lastIndexReaderId = indexes.size() - 1;
+ lastIndexReader = ((PersistentIndex)indexes.get(lastIndexReaderId)).getReadOnlyIndexReader();
+ }
+ // if indexReader exists (it is possible that no persisted indexes exists on start)
+ if (lastIndexReader != null)
+ {
+ try
+ {
+ // reader from resisted index should be
+ TermDocs termDocs = lastIndexReader.termDocs(new Term(FieldNames.UUID, uuid));
+ // node should be indexed if not found in persistent index
+ addDoc = termDocs == null;
+ }
+ catch (Exception e)
+ {
+ log.debug("Some exception occured, during index check");
+ }
+ }
+ }
+
+ if (addDoc)
+ {
+ volatileIndex.addDocuments(new Document[]{doc});
+ // reset volatile index if needed
+ if (volatileIndex.getRamSizeInBytes() >= handler.getMaxVolatileIndexSize())
+ {
+ // to avoid out of memory
+ resetVolatileIndex();
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ // don't forget to release a reader anyway
+ if (lastIndexReader != null)
+ {
+ lastIndexReader.release();
+ }
+ synchronized (updateMonitor)
+ {
+ releaseMultiReader();
+ }
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
+ * For investigation purposes only
+ *
+ * @param remove
+ * @param add
+ * @throws IOException
+ */
+ private void doUpdateRW(final Collection remove, final Collection add) throws IOException
+ {
+ SecurityHelper.doPrivilegedIOExceptionAction(new PrivilegedExceptionAction<Object>()
+ {
+ public Object run() throws Exception
+ {
+ // make sure a reader is available during long updates
+ if (add.size() > handler.getBufferSize())
+ {
+ try
+ {
+ getIndexReader().release();
+ }
+ catch (IOException e)
+ {
+ // do not fail if an exception is thrown here
+ log.warn("unable to prepare index reader " + "for queries during update", e);
+ }
+ }
+
synchronized (updateMonitor)
{
//updateInProgress = true;
@@ -2636,7 +2772,7 @@
// if the document cannot be deleted from the volatile index
// delete it from one of the persistent indexes.
int num = index.volatileIndex.removeDocument(idTerm);
- if (num == 0)
+ if (num == 0 && index.modeHandler.getMode() == IndexerIoMode.READ_WRITE)
{
for (int i = index.indexes.size() - 1; i >= 0; i--)
{
@@ -2946,6 +3082,10 @@
{
synchronized (updateMonitor)
{
+ // Coordinator set cluster-wide updateInProgress only in case of persistent flush, which
+ // invokes volatile reset. So if RO cluster node received this notification, it means that
+ // coordinator flushed volatile.
+ resetVolatileIndex();
updateMonitor.notifyAll();
releaseMultiReader();
}
@@ -3178,4 +3318,4 @@
}
}
}
-}
+}
\ No newline at end of file
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -738,11 +738,28 @@
IOException
{
checkOpen();
+ apply(getChanges(remove, add));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void apply(ChangesHolder changes) throws RepositoryException, IOException
+ {
+ checkOpen();
+ index.update(changes.getRemove(), changes.getAdd());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ChangesHolder getChanges(Iterator<String> remove, Iterator<NodeData> add)
+ {
final Map<String, NodeData> aggregateRoots = new HashMap<String, NodeData>();
final Set<String> removedNodeIds = new HashSet<String>();
final Set<String> addedNodeIds = new HashSet<String>();
- index.update(IteratorUtils.toList(new TransformIterator(remove, new Transformer()
+ Collection<String> docIdsToRemove = IteratorUtils.toList(new TransformIterator(remove, new Transformer()
{
public Object transform(Object input)
{
@@ -750,7 +767,8 @@
removedNodeIds.add(uuid);
return uuid;
}
- })), IteratorUtils.toList(new TransformIterator(add, new Transformer()
+ }));
+ Collection<Document> docsToAdd = IteratorUtils.toList(new TransformIterator(add, new Transformer()
{
public Object transform(Object input)
{
@@ -775,7 +793,7 @@
}
return doc;
}
- })));
+ }));
// remove any aggregateRoot nodes that are new
// and therefore already up-to-date
@@ -805,8 +823,14 @@
}
});
modified.addAll(aggregateRoots.values());
- index.update(aggregateRoots.keySet(), modified);
+ docIdsToRemove.addAll(aggregateRoots.keySet());
+ docsToAdd.addAll(modified);
}
+ if (docIdsToRemove.isEmpty() && docsToAdd.isEmpty())
+ {
+ return null;
+ }
+ return new ChangesHolder(docIdsToRemove, docsToAdd);
}
/**
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SingletonTokenStream.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SingletonTokenStream.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SingletonTokenStream.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -16,64 +16,78 @@
*/
package org.exoplatform.services.jcr.impl.core.query.lucene;
-import java.io.IOException;
-
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.index.Payload;
+import java.io.IOException;
+import java.io.Serializable;
+
/**
* <code>SingletonTokenStream</code> implements a token stream that wraps a
* single value with a given property type. The property type is stored as a
* payload on the single returned token.
*/
-public final class SingletonTokenStream extends TokenStream {
+public final class SingletonTokenStream extends TokenStream implements Serializable
+{
- /**
- * The string value of the token.
- */
- private String value;
+ /**
+ * The string value of the token.
+ */
+ private String value;
- /**
- * The payload of the token.
- */
- private final Payload payload;
+ /**
+ * The payload of the token.
+ */
+ private Payload payload;
- /**
- * Creates a new SingleTokenStream with the given value and a property
- * <code>type</code>.
- *
- * @param value the string value that will be returned with the token.
- * @param type the JCR property type.
- */
- public SingletonTokenStream(String value, int type) {
- this.value = value;
- this.payload = new Payload(new PropertyMetaData(type).toByteArray());
- }
+ /**
+ * for serialization
+ */
+ public SingletonTokenStream()
+ {
+ // TODO Auto-generated constructor stub
+ }
- /**
- * Creates a new SingleTokenStream with the given token.
- *
- * @param t the token.
- */
- public SingletonTokenStream(Token t) {
- this.value = t.term();
- this.payload = t.getPayload();
- }
+ /**
+ * Creates a new SingleTokenStream with the given value and a property
+ * <code>type</code>.
+ *
+ * @param value the string value that will be returned with the token.
+ * @param type the JCR property type.
+ */
+ public SingletonTokenStream(String value, int type)
+ {
+ this.value = value;
+ this.payload = new Payload(new PropertyMetaData(type).toByteArray());
+ }
- /**
- * {@inheritDoc}
- */
- public Token next(Token reusableToken) throws IOException {
- if (value == null) {
- return null;
- }
- reusableToken.clear();
- reusableToken.setTermBuffer(value);
- reusableToken.setPayload(payload);
- reusableToken.setStartOffset(0);
- reusableToken.setEndOffset(value.length());
- value = null;
- return reusableToken;
- }
+ /**
+ * Creates a new SingleTokenStream with the given token.
+ *
+ * @param t the token.
+ */
+ public SingletonTokenStream(Token t)
+ {
+ this.value = t.term();
+ this.payload = t.getPayload();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Token next(Token reusableToken) throws IOException
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ reusableToken.clear();
+ reusableToken.setTermBuffer(value);
+ reusableToken.setPayload(payload);
+ reusableToken.setStartOffset(0);
+ reusableToken.setEndOffset(value.length());
+ value = null;
+ return reusableToken;
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java 2011-02-16 09:00:20 UTC (rev 3979)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -23,9 +23,11 @@
import org.exoplatform.services.jcr.impl.core.query.AbstractQueryHandler;
import org.exoplatform.services.jcr.impl.core.query.ExecutableQuery;
import org.exoplatform.services.jcr.impl.core.query.QueryHandlerContext;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
import java.io.IOException;
+import java.util.Iterator;
import java.util.Set;
import javax.jcr.RepositoryException;
@@ -92,4 +94,16 @@
// TODO Auto-generated method stub
return null;
}
+
+ public void apply(ChangesHolder changes) throws RepositoryException, IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public ChangesHolder getChanges(Iterator<String> remove, Iterator<NodeData> add)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/query/lucene/TestChangesHolder.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/query/lucene/TestChangesHolder.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/core/query/lucene/TestChangesHolder.java 2011-02-16 10:02:16 UTC (rev 3980)
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.core.query.lucene;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Field.Index;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.document.Field.TermVector;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public class TestChangesHolder extends TestCase
+{
+
+ public void testSerNDeserializeDocs() throws Exception
+ {
+ System.out.println("### testSerNDeserializeDocs ###");
+ Collection<Document> add = new ArrayList<Document>(3);
+ Document doc = new Document();
+ doc.setBoost(2.0f);
+ Field fieldFull = new Field("full", "full-value", Store.COMPRESS, Index.ANALYZED_NO_NORMS, TermVector.WITH_POSITIONS_OFFSETS);
+ fieldFull.setBoost(2.0f);
+ fieldFull.setOmitTf(true);
+ doc.add(fieldFull);
+ Field fieldEmpty = new Field("empty", "empty-value", Store.NO, Index.NOT_ANALYZED, TermVector.NO);
+ doc.add(fieldEmpty);
+ add.add(doc);
+ doc = new Document();
+ doc.add(fieldFull);
+ add.add(doc);
+ doc = new Document();
+ doc.add(fieldEmpty);
+ add.add(doc);
+
+ ByteArrayOutputStream baos = null;
+
+ int total = 100000;
+ long start;
+ Collection<String> remove = Collections.emptyList();
+ Collection<Document> addResult = null;
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(new ChangesHolder(remove, add));
+ oos.close();
+ }
+ System.out.println("Custom serialization: total time = " + (System.currentTimeMillis() - start) + ", size = " + baos.size());
+
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ addResult = ((ChangesHolder)ois.readObject()).getAdd();
+ ois.close();
+ }
+ System.out.println("Custom deserialization: total time = " + (System.currentTimeMillis() - start));
+ checkDocs(addResult);
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(add);
+ oos.close();
+ }
+ System.out.println("Native serialization: total time = " + (System.currentTimeMillis() - start) + ", size = " + baos.size());
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ addResult = (Collection<Document>)ois.readObject();
+ ois.close();
+ }
+ System.out.println("Native deserialization: total time = " + (System.currentTimeMillis() - start));
+ checkDocs(addResult);
+ }
+
+ private void checkDocs(Collection<Document> addResult)
+ {
+ assertNotNull(addResult);
+ assertEquals(3, addResult.size());
+ Iterator<Document> it = addResult.iterator();
+ Document doc = it.next();
+ assertEquals(2.0f, doc.getBoost());
+ List<Field> fields = doc.getFields();
+ assertNotNull(fields);
+ assertEquals(2, fields.size());
+ checkFieldFull(fields.get(0));
+ checkFieldEmpty(fields.get(1));
+ doc = it.next();
+ assertEquals(1.0f, doc.getBoost());
+ fields = doc.getFields();
+ assertNotNull(fields);
+ assertEquals(1, fields.size());
+ checkFieldFull(fields.get(0));
+ doc = it.next();
+ assertEquals(1.0f, doc.getBoost());
+ fields = doc.getFields();
+ assertNotNull(fields);
+ assertEquals(1, fields.size());
+ checkFieldEmpty(fields.get(0));
+ }
+
+ private void checkFieldFull(Field field)
+ {
+ assertEquals("full", field.name());
+ assertEquals("full-value", field.stringValue());
+ assertTrue(field.isStored());
+ assertTrue(field.isCompressed());
+ assertTrue(field.isIndexed());
+ assertTrue(field.isTokenized());
+ assertTrue(field.getOmitNorms());
+ assertTrue(field.isTermVectorStored());
+ assertTrue(field.isStoreOffsetWithTermVector());
+ assertTrue(field.isStorePositionWithTermVector());
+ assertTrue(field.getOmitTf());
+ assertFalse(field.isBinary());
+ assertFalse(field.isLazy());
+ assertEquals(2.0f, field.getBoost());
+ assertEquals(0, field.getBinaryLength());
+ assertEquals(0, field.getBinaryOffset());
+ }
+
+ private void checkFieldEmpty(Field field)
+ {
+ assertEquals("empty", field.name());
+ assertEquals("empty-value", field.stringValue());
+ assertFalse(field.isStored());
+ assertFalse(field.isCompressed());
+ assertTrue(field.isIndexed());
+ assertFalse(field.isTokenized());
+ assertFalse(field.getOmitNorms());
+ assertFalse(field.isTermVectorStored());
+ assertFalse(field.isStoreOffsetWithTermVector());
+ assertFalse(field.isStorePositionWithTermVector());
+ assertFalse(field.getOmitTf());
+ assertFalse(field.isBinary());
+ assertFalse(field.isLazy());
+ assertEquals(1.0f, field.getBoost());
+ assertEquals(0, field.getBinaryLength());
+ assertEquals(0, field.getBinaryOffset());
+ }
+
+ public void testSerNDeserializeIds() throws Exception
+ {
+ System.out.println("### testSerNDeserializeIds ###");
+ Collection<String> remove = new ArrayList<String>(3);
+ remove.add(UUID.randomUUID().toString());
+ remove.add(UUID.randomUUID().toString());
+ remove.add(UUID.randomUUID().toString());
+ ByteArrayOutputStream baos = null;
+
+ int total = 100000;
+ long start;
+ Collection<Document> add = Collections.emptyList();
+ Collection<String> addResult = null;
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(new ChangesHolder(remove, add));
+ oos.close();
+ }
+ System.out.println("Custom serialization: total time = " + (System.currentTimeMillis() - start) + ", size = " + baos.size());
+
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ addResult = ((ChangesHolder)ois.readObject()).getRemove();
+ ois.close();
+ }
+ System.out.println("Custom deserialization: total time = " + (System.currentTimeMillis() - start));
+ checkIds(remove, addResult);
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(remove);
+ oos.close();
+ }
+ System.out.println("Native serialization: total time = " + (System.currentTimeMillis() - start) + ", size = " + baos.size());
+ start = System.currentTimeMillis();
+ for (int i = 0; i < total; i++)
+ {
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ addResult = (Collection<String>)ois.readObject();
+ ois.close();
+ }
+ System.out.println("Native deserialization: total time = " + (System.currentTimeMillis() - start));
+ checkIds(remove, addResult);
+ }
+
+ private void checkIds(Collection<String> remove, Collection<String> addResult)
+ {
+ assertNotNull(addResult);
+ assertEquals(remove.size(), addResult.size());
+ Iterator<String> it1 = remove.iterator();
+ Iterator<String> it2 = addResult.iterator();
+ while (it1.hasNext())
+ {
+ assertEquals(it1.next(), it2.next());
+ }
+ }
+}
13 years, 3 months
exo-jcr SVN: r3979 - jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581.
by do-not-reply@jboss.org
Author: dkuleshov
Date: 2011-02-16 04:00:20 -0500 (Wed, 16 Feb 2011)
New Revision: 3979
Modified:
jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch
Log:
JCR-1581: updated patch
Modified: jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch
===================================================================
--- jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch 2011-02-15 14:14:38 UTC (rev 3978)
+++ jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch 2011-02-16 09:00:20 UTC (rev 3979)
@@ -1,299 +1,18 @@
-Index: exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
---- exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml (revision 3974)
-+++ exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml (working copy)
-@@ -100,6 +100,7 @@
- <property name="jgroups-multiplexer-stack" value="true" />
- <property name="jbosscache-cluster-name" value="JCR-cluster-indexer-ws" />
- <property name="max-volatile-time" value="60" />
-+ <property name="io-exception-retry-count" value="5" />
- </properties>
- </query-handler>
- </workspace></programlisting> <table>
-@@ -154,6 +155,13 @@
-
- <entry>max time to live for Volatile Index</entry>
- </row>
-+
-+ <row>
-+ <entry>io-exception-retry-count</entry>
-+
-+ <entry>IOException retries maximum number on index reader
-+ instantiation. Default value is 3</entry>
-+ </row>
- </tbody>
- </tgroup>
- </table></para>
-Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
-===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java (revision 3974)
-+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java (working copy)
-@@ -186,5 +186,9 @@
- {
- searchIndex.setSpellCheckerMinDistance(StringNumberParser.parseNumber(value).floatValue());
- }
-+ else if (QueryHandlerParams.PARAM_IO_EXCEPTION_RETRY_COUNT.equals(name))
-+ {
-+ searchIndex.setIoExceptionRetryCount(StringNumberParser.parseNumber(value).intValue());
-+ }
- }
- }
-Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
-===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (revision 3974)
-+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (working copy)
-@@ -92,6 +92,13 @@
- public class SearchIndex extends AbstractQueryHandler implements IndexerIoModeListener
- {
-
-+ /**
-+ * Default number of how many retries are going to be
-+ * while encountering io exception during query execution
-+ * see https://jira.exoplatform.org/browse/JCR-1581 for more details
-+ */
-+ private static final int DEFAULT_IO_EXCEPTION_RETRY_COUNT = 3;
-+
- private static final DefaultQueryNodeFactory DEFAULT_QUERY_NODE_FACTORY = new DefaultQueryNodeFactory();
-
- /** The logger instance for this class */
-@@ -168,6 +175,13 @@
- private static final String ERROR_LOG = "error.log";
-
- /**
-+ * Number of how many retries are going to be
-+ * while encountering io exception during query execution
-+ * see https://jira.exoplatform.org/browse/JCR-1581 for more details
-+ */
-+ private int ioExceptionRetryCount = DEFAULT_IO_EXCEPTION_RETRY_COUNT;
-+
-+ /**
- * The actual index
- */
- private MultiIndex index;
-@@ -611,6 +625,25 @@
- }
-
- /**
-+ * Sets ioExceptionRetryCount
-+ * @param count
-+ */
-+ public void setIoExceptionRetryCount(int count)
-+ {
-+ if (count > 0)
-+ ioExceptionRetryCount = count;
-+ }
-+
-+ /**
-+ * Gets ioExceptionRetryCount
-+ * @return ioExceptionRetryCount
-+ */
-+ public int getIoExceptionRetryCount()
-+ {
-+ return ioExceptionRetryCount;
-+ }
-+
-+ /**
- * @return the errorLogfileSize
- */
- public int getErrorLogfileSize()
-@@ -708,8 +741,7 @@
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java (revision 3978)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java (working copy)
+@@ -784,6 +784,13 @@
+ // when reindexing the final commit is done at the very end
+ executeAndLog(new Commit(getTransactionId()));
}
- catch (RepositoryException e)
- {
-- log
-- .warn("Exception while creating document for node: " + state.getIdentifier() + ": " + e.toString(), e);
-+ log.warn("Exception while creating document for node: " + state.getIdentifier() + ": " + e.toString(), e);
- }
- return doc;
++ // force IndexInfos (IndexNames) to be written on FS and both be replicated over cluster
++ // for non-coordinator cluster nodes be notified of new index list ASAP. This may avoid race
++ // conditions when coordinator invokes flush() which performs indexNames.write()
++ // and deletes obsolete index just after. Making this list be written now, will notify non-
++ // coordinator node about new merged index and obsolete indexes long time before they will
++ // be deleted.
++ indexNames.write();
}
-@@ -736,8 +768,7 @@
- }
- catch (RepositoryException e)
- {
-- log
-- .warn("Exception while creating document for node: " + state.getIdentifier() + ": " + e.toString());
-+ log.warn("Exception while creating document for node: " + state.getIdentifier() + ": " + e.toString());
- }
- return null;
- }
-@@ -870,25 +901,45 @@
-
- Sort sort = new Sort(createSortFields(orderProps, orderSpecs));
-
-- final IndexReader reader = getIndexReader(queryImpl.needsSystemTree());
-- JcrIndexSearcher searcher = new JcrIndexSearcher(session, reader, getContext().getItemStateManager());
-- searcher.setSimilarity(getSimilarity());
-- return new FilterMultiColumnQueryHits(searcher.execute(query, sort, resultFetchHint,
-- QueryImpl.DEFAULT_SELECTOR_NAME))
-+ for (int i = 0; i < ioExceptionRetryCount; i++)
- {
-- public void close() throws IOException
-+ final IndexReader reader = getIndexReader(queryImpl.needsSystemTree());
-+ try
+ finally
{
-+ JcrIndexSearcher searcher = new JcrIndexSearcher(session, reader, getContext().getItemStateManager());
-+ searcher.setSimilarity(getSimilarity());
-+ return new FilterMultiColumnQueryHits(searcher.execute(query, sort, resultFetchHint,
-+ QueryImpl.DEFAULT_SELECTOR_NAME))
-+ {
-+ public void close() throws IOException
-+ {
-+ try
-+ {
-+ super.close();
-+ }
-+ finally
-+ {
-+ PerQueryCache.getInstance().dispose();
-+ Util.closeOrRelease(reader);
-+ }
-+ }
-+ };
-+ }
-+ catch (IOException e)
-+ {
- try
- {
-- super.close();
-+ Util.closeOrRelease(reader);
- }
-- finally
-+ catch (Exception releaseException)
- {
-- PerQueryCache.getInstance().dispose();
-- Util.closeOrRelease(reader);
-+ log.warn("Error occured while closing or releasing a reader", releaseException);
- }
- }
-- };
-+ }
-+
-+ throw new IOException("IO exception was encountered more than " + ioExceptionRetryCount + " times");
-+
- }
-
- /**
-@@ -918,24 +969,43 @@
-
- Sort sort = new Sort(createSortFields(orderProps, orderSpecs));
-
-- final IndexReader reader = getIndexReader();
-- JcrIndexSearcher searcher = new JcrIndexSearcher(session, reader, getContext().getItemStateManager());
-- searcher.setSimilarity(getSimilarity());
-- return new FilterMultiColumnQueryHits(query.execute(searcher, sort, resultFetchHint))
-+ for (int i = 0; i < ioExceptionRetryCount; i++)
- {
-- public void close() throws IOException
-+ final IndexReader reader = getIndexReader();
-+ try
- {
-+ JcrIndexSearcher searcher = new JcrIndexSearcher(session, reader, getContext().getItemStateManager());
-+ searcher.setSimilarity(getSimilarity());
-+ return new FilterMultiColumnQueryHits(query.execute(searcher, sort, resultFetchHint))
-+ {
-+ public void close() throws IOException
-+ {
-+ try
-+ {
-+ super.close();
-+ }
-+ finally
-+ {
-+ PerQueryCache.getInstance().dispose();
-+ Util.closeOrRelease(reader);
-+ }
-+ }
-+ };
-+ }
-+ catch (IOException e)
-+ {
- try
- {
-- super.close();
-+ Util.closeOrRelease(reader);
- }
-- finally
-+ catch (Exception releaseException)
- {
-- PerQueryCache.getInstance().dispose();
-- Util.closeOrRelease(reader);
-+ log.warn("Error occured while closing or releasing a reader", releaseException);
- }
- }
-- };
-+ }
-+
-+ throw new IOException("IO exception was encountered more than " + ioExceptionRetryCount + " times");
- }
-
- /**
-@@ -1330,8 +1400,8 @@
- {
- File root = new File(path, synonymProviderConfigPath.substring(0, lastSeparator));
- fsr =
-- new BufferedInputStream(new FileInputStream(new File(root, synonymProviderConfigPath
-- .substring(lastSeparator + 1))));
-+ new BufferedInputStream(new FileInputStream(new File(root,
-+ synonymProviderConfigPath.substring(lastSeparator + 1))));
- }
- else
- {
-@@ -1540,8 +1610,7 @@
- catch (Exception e)
- {
- // do not fail if aggregate cannot be created
-- log
-- .warn("Exception while building indexing aggregate for" + " node with UUID: " + state.getIdentifier(), e);
-+ log.warn("Exception while building indexing aggregate for" + " node with UUID: " + state.getIdentifier(), e);
- }
- }
- }
-@@ -2712,11 +2781,32 @@
- {
- checkOpen();
-
-- IndexReader reader = getIndexReader(true);
-- IndexSearcher searcher = new IndexSearcher(reader);
-- searcher.setSimilarity(getSimilarity());
-+ IndexReader reader;
-
-- return new LuceneQueryHits(reader, searcher, query);
-+ for (int i = 0; i < ioExceptionRetryCount; i++)
-+ {
-+ reader = getIndexReader(true);
-+ try
-+ {
-+ IndexSearcher searcher = new IndexSearcher(reader);
-+ searcher.setSimilarity(getSimilarity());
-+
-+ return new LuceneQueryHits(reader, searcher, query);
-+ }
-+ catch (IOException e)
-+ {
-+ try
-+ {
-+ Util.closeOrRelease(reader);
-+ }
-+ catch (Exception releaseException)
-+ {
-+ log.warn("Error occured while closing or releasing a reader", releaseException);
-+ }
-+ }
-+ }
-+
-+ throw new IOException("IO exception was encountered more than " + ioExceptionRetryCount + " times");
- }
-
- /**
-Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java
-===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java (revision 3974)
-+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java (working copy)
-@@ -114,4 +114,7 @@
- public static final String PARAM_JBOSSCACHE_PUSHSTATE = "jbosscache-sscl-push.state.enabled";
-
- public static final String PARAM_JBOSSCACHE_PUSHSTATE_TIMEOUT = "jbosscache-sscl-push.state.timeout";
-+
-+ public static final String PARAM_IO_EXCEPTION_RETRY_COUNT = "io-exception-retry-count";
-+
- }
13 years, 3 months
exo-jcr SVN: r3978 - in ws/trunk/exo.ws.rest.core/src: test/java/org/exoplatform/services/rest/impl and 1 other directory.
by do-not-reply@jboss.org
Author: aparfonov
Date: 2011-02-15 09:14:38 -0500 (Tue, 15 Feb 2011)
New Revision: 3978
Modified:
ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/FieldInjectorImpl.java
ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/InjectAnnotationTest.java
Log:
EXOJCR-1181
Modified: ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/FieldInjectorImpl.java
===================================================================
--- ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/FieldInjectorImpl.java 2011-02-15 13:39:35 UTC (rev 3977)
+++ ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/FieldInjectorImpl.java 2011-02-15 14:14:38 UTC (rev 3978)
@@ -26,10 +26,13 @@
import org.exoplatform.services.rest.resource.ResourceDescriptorVisitor;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.util.List;
import javax.ws.rs.DefaultValue;
@@ -69,6 +72,8 @@
/** See {@link java.lang.reflect.Field} . */
private final java.lang.reflect.Field jfield;
+ private final Method setter;
+
/**
* @param resourceClass class that contains field <tt>jfield</tt>
* @param jfield java.lang.reflect.Field
@@ -77,6 +82,7 @@
{
this.jfield = jfield;
this.annotations = jfield.getDeclaredAnnotations();
+ this.setter = getSetter(resourceClass, jfield);
Annotation annotation = null;
String defaultValue = null;
@@ -130,6 +136,27 @@
this.encoded = encoded || resourceClass.getAnnotation(Encoded.class) != null;
}
+ private static Method getSetter(final Class<?> clazz, final java.lang.reflect.Field jfield)
+ {
+ Method setter = null;
+ try
+ {
+ setter = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
+ public Method run() throws NoSuchMethodException
+ {
+ String name = jfield.getName();
+ String setterName = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
+ return clazz.getMethod(setterName, jfield.getType());
+ }
+ });
+ }
+ catch (PrivilegedActionException e)
+ {
+ // Ignore NoSuchMethodException.
+ }
+ return setter;
+ }
+
/**
* {@inheritDoc}
*/
@@ -196,17 +223,24 @@
ParameterResolver<?> pr = ParameterResolverFactory.createParameterResolver(annotation);
try
{
- if (!Modifier.isPublic(jfield.getModifiers()))
+ if (setter != null)
{
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run()
- {
- jfield.setAccessible(true);
- return null;
- }
- });
+ setter.invoke(resource, pr.resolve(this, context));
}
- jfield.set(resource, pr.resolve(this, context));
+ else
+ {
+ if (!Modifier.isPublic(jfield.getModifiers()))
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run()
+ {
+ jfield.setAccessible(true);
+ return null;
+ }
+ });
+ }
+ jfield.set(resource, pr.resolve(this, context));
+ }
}
catch (Throwable e)
{
@@ -223,17 +257,24 @@
{
try
{
- if (!Modifier.isPublic(jfield.getModifiers()))
+ if (setter != null)
{
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run()
- {
- jfield.setAccessible(true);
- return null;
- }
- });
+ setter.invoke(resource, tmp);
}
- jfield.set(resource, tmp);
+ else
+ {
+ if (!Modifier.isPublic(jfield.getModifiers()))
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run()
+ {
+ jfield.setAccessible(true);
+ return null;
+ }
+ });
+ }
+ jfield.set(resource, tmp);
+ }
}
catch (Throwable e)
{
Modified: ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/InjectAnnotationTest.java
===================================================================
--- ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/InjectAnnotationTest.java 2011-02-15 13:39:35 UTC (rev 3977)
+++ ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/InjectAnnotationTest.java 2011-02-15 14:14:38 UTC (rev 3978)
@@ -80,6 +80,28 @@
}
}
+ @Path("a")
+ public static class Resource3
+ {
+ @Inject
+ private GenericIngectable<String> injected;
+ private boolean injectedThroughSetter = false;
+
+ @GET
+ public String m()
+ {
+ assertNotNull(injected);
+ assertTrue(injectedThroughSetter);
+ return ((InjectableComponent)injected).message;
+ }
+
+ public void setInjected(GenericIngectable<String> injected)
+ {
+ this.injectedThroughSetter = true;
+ this.injected = injected;
+ }
+ }
+
public void testInjectFromContainer() throws Exception
{
container.registerComponentInstance(InjectableComponent.class.getName(), new InjectableComponent());
@@ -112,4 +134,15 @@
unregistry(Resource2.class);
container.unregisterComponent(Provider90.class.getName());
}
+
+ public void testInjectWithSetter() throws Exception
+ {
+ container.registerComponentInstance(InjectableComponent.class.getName(), new InjectableComponent());
+ registry(Resource3.class);
+ ContainerResponse response = launcher.service("GET", "/a", "", null, null, null);
+ assertEquals(200, response.getStatus());
+ assertEquals("injected from container", response.getEntity());
+ unregistry(Resource3.class);
+ container.unregisterComponent(InjectableComponent.class.getName());
+ }
}
13 years, 3 months
exo-jcr SVN: r3977 - in jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc: indexing and 1 other directories.
by do-not-reply@jboss.org
Author: nfilotto
Date: 2011-02-15 08:39:35 -0500 (Tue, 15 Feb 2011)
New Revision: 3977
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/db/GenericConnectionFactory.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2ConnectionFactory.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2MultiDbJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2SingleDbJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DefaultOracleConnectionFactory.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLConnectionFactory.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLMultiDbJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLSingleDbJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleMultiDbJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleSingleDbJDBCConnection.java
Log:
EXOJCR-1104: Fix bug that prevents the paging to work properly when no node id is required. In case of Oracle, MSSQL and DB2, we expect an offset not a limit.
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/db/GenericConnectionFactory.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/db/GenericConnectionFactory.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/db/GenericConnectionFactory.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -271,4 +271,13 @@
{
return false;
}
+
+ /**
+ * Indicates whether the id of the last item is needed for paging
+ * @return <code>true</code> if the id is needed, <code>false</code> otherwise.
+ */
+ public boolean isIDNeededForPaging()
+ {
+ return true;
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -113,7 +113,7 @@
{
currentOffset = offset.getAndAdd(pageSize);
currentLastNodeId = lastNodeId.get();
- currentPage = page.incrementAndGet();
+ currentPage = page.incrementAndGet();
}
long time = System.currentTimeMillis();
List<NodeDataIndexing> result = conn.getNodesAndProperties(currentLastNodeId, currentOffset, pageSize);
@@ -125,7 +125,7 @@
+ (result.isEmpty() ? "unknown" : result.get(result.size() - 1).getIdentifier()) + "'");
}
hasNext.compareAndSet(true, result.size() == pageSize);
- if (hasNext())
+ if (hasNext() && connFactory.isIDNeededForPaging())
{
synchronized (this)
{
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2ConnectionFactory.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2ConnectionFactory.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2ConnectionFactory.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -122,4 +122,13 @@
throw new RepositoryException(e);
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isIDNeededForPaging()
+ {
+ return false;
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2MultiDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2MultiDbJDBCConnection.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2MultiDbJDBCConnection.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -93,7 +93,7 @@
findNodesAndProperties.clearParameters();
}
- findNodesAndProperties.setInt(1, limit);
+ findNodesAndProperties.setInt(1, offset + limit);
findNodesAndProperties.setInt(2, offset);
return findNodesAndProperties.executeQuery();
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2SingleDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2SingleDbJDBCConnection.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DB2SingleDbJDBCConnection.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -95,7 +95,7 @@
}
findNodesAndProperties.setString(1, containerName);
- findNodesAndProperties.setInt(2, limit);
+ findNodesAndProperties.setInt(2, offset + limit);
findNodesAndProperties.setInt(3, offset);
findNodesAndProperties.setString(4, containerName);
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DefaultOracleConnectionFactory.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DefaultOracleConnectionFactory.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/DefaultOracleConnectionFactory.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -136,4 +136,13 @@
throw new RepositoryException(e);
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isIDNeededForPaging()
+ {
+ return false;
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLConnectionFactory.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLConnectionFactory.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLConnectionFactory.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -122,4 +122,13 @@
throw new RepositoryException(e);
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isIDNeededForPaging()
+ {
+ return false;
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLMultiDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLMultiDbJDBCConnection.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLMultiDbJDBCConnection.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -91,7 +91,7 @@
findNodesAndProperties.clearParameters();
}
- findNodesAndProperties.setInt(1, limit);
+ findNodesAndProperties.setInt(1, offset + limit);
findNodesAndProperties.setInt(2, offset);
return findNodesAndProperties.executeQuery();
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLSingleDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLSingleDbJDBCConnection.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MSSQLSingleDbJDBCConnection.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -95,7 +95,7 @@
}
findNodesAndProperties.setString(1, containerName);
- findNodesAndProperties.setInt(2, limit);
+ findNodesAndProperties.setInt(2, offset + limit);
findNodesAndProperties.setInt(3, offset);
findNodesAndProperties.setString(4, containerName);
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleMultiDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleMultiDbJDBCConnection.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleMultiDbJDBCConnection.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -104,7 +104,7 @@
findNodesAndProperties.clearParameters();
}
- findNodesAndProperties.setInt(1, limit);
+ findNodesAndProperties.setInt(1, offset + limit);
findNodesAndProperties.setInt(2, offset);
return findNodesAndProperties.executeQuery();
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleSingleDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleSingleDbJDBCConnection.java 2011-02-15 10:04:43 UTC (rev 3976)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/OracleSingleDbJDBCConnection.java 2011-02-15 13:39:35 UTC (rev 3977)
@@ -107,7 +107,7 @@
}
findNodesAndProperties.setString(1, containerName);
- findNodesAndProperties.setInt(2, limit);
+ findNodesAndProperties.setInt(2, offset + limit);
findNodesAndProperties.setInt(3, offset);
findNodesAndProperties.setString(4, containerName);
13 years, 3 months
exo-jcr SVN: r3976 - jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581.
by do-not-reply@jboss.org
Author: dkuleshov
Date: 2011-02-15 05:04:43 -0500 (Tue, 15 Feb 2011)
New Revision: 3976
Modified:
jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch
Log:
JCR-1581: docbook modified in accordance to new param
Modified: jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch
===================================================================
--- jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch 2011-02-15 09:34:20 UTC (rev 3975)
+++ jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch 2011-02-15 10:04:43 UTC (rev 3976)
@@ -1,6 +1,32 @@
+Index: exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml
+===================================================================
+--- exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml (revision 3974)
++++ exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/query-handler-config.xml (working copy)
+@@ -100,6 +100,7 @@
+ <property name="jgroups-multiplexer-stack" value="true" />
+ <property name="jbosscache-cluster-name" value="JCR-cluster-indexer-ws" />
+ <property name="max-volatile-time" value="60" />
++ <property name="io-exception-retry-count" value="5" />
+ </properties>
+ </query-handler>
+ </workspace></programlisting> <table>
+@@ -154,6 +155,13 @@
+
+ <entry>max time to live for Volatile Index</entry>
+ </row>
++
++ <row>
++ <entry>io-exception-retry-count</entry>
++
++ <entry>IOException retries maximum number on index reader
++ instantiation. Default value is 3</entry>
++ </row>
+ </tbody>
+ </tgroup>
+ </table></para>
Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java (revision 3973)
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java (revision 3974)
+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java (working copy)
@@ -186,5 +186,9 @@
{
@@ -14,7 +40,7 @@
}
Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (revision 3973)
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (revision 3974)
+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (working copy)
@@ -92,6 +92,13 @@
public class SearchIndex extends AbstractQueryHandler implements IndexerIoModeListener
@@ -261,7 +287,7 @@
/**
Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java
===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java (revision 3973)
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java (revision 3974)
+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java (working copy)
@@ -114,4 +114,7 @@
public static final String PARAM_JBOSSCACHE_PUSHSTATE = "jbosscache-sscl-push.state.enabled";
13 years, 3 months
exo-jcr SVN: r3975 - jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581.
by do-not-reply@jboss.org
Author: dkuleshov
Date: 2011-02-15 04:34:20 -0500 (Tue, 15 Feb 2011)
New Revision: 3975
Modified:
jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch
Log:
JCR-1581: patch updated
Modified: jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch
===================================================================
--- jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch 2011-02-15 09:03:38 UTC (rev 3974)
+++ jcr/branches/1.12.x/patch/1.12.8-GA/JCR-1581/JCR-1581.patch 2011-02-15 09:34:20 UTC (rev 3975)
@@ -1,17 +1,76 @@
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java (revision 3973)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java (working copy)
+@@ -186,5 +186,9 @@
+ {
+ searchIndex.setSpellCheckerMinDistance(StringNumberParser.parseNumber(value).floatValue());
+ }
++ else if (QueryHandlerParams.PARAM_IO_EXCEPTION_RETRY_COUNT.equals(name))
++ {
++ searchIndex.setIoExceptionRetryCount(StringNumberParser.parseNumber(value).intValue());
++ }
+ }
+ }
Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (revision 3961)
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (revision 3973)
+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java (working copy)
-@@ -122,6 +122,8 @@
+@@ -92,6 +92,13 @@
+ public class SearchIndex extends AbstractQueryHandler implements IndexerIoModeListener
+ {
+
++ /**
++ * Default number of how many retries are going to be
++ * while encountering io exception during query execution
++ * see https://jira.exoplatform.org/browse/JCR-1581 for more details
++ */
++ private static final int DEFAULT_IO_EXCEPTION_RETRY_COUNT = 3;
++
+ private static final DefaultQueryNodeFactory DEFAULT_QUERY_NODE_FACTORY = new DefaultQueryNodeFactory();
+
+ /** The logger instance for this class */
+@@ -168,6 +175,13 @@
+ private static final String ERROR_LOG = "error.log";
+
+ /**
++ * Number of how many retries are going to be
++ * while encountering io exception during query execution
++ * see https://jira.exoplatform.org/browse/JCR-1581 for more details
++ */
++ private int ioExceptionRetryCount = DEFAULT_IO_EXCEPTION_RETRY_COUNT;
++
++ /**
+ * The actual index
*/
- public static final int DEFAULT_MAX_FIELD_LENGTH = 10000;
+ private MultiIndex index;
+@@ -611,6 +625,25 @@
+ }
-+ private static final int IOEXCEPTION_RETRY_COUNT = 3;
+ /**
++ * Sets ioExceptionRetryCount
++ * @param count
++ */
++ public void setIoExceptionRetryCount(int count)
++ {
++ if (count > 0)
++ ioExceptionRetryCount = count;
++ }
+
- /**
- * The default value for property {@link #extractorPoolSize}.
- *
-@@ -708,8 +710,7 @@
++ /**
++ * Gets ioExceptionRetryCount
++ * @return ioExceptionRetryCount
++ */
++ public int getIoExceptionRetryCount()
++ {
++ return ioExceptionRetryCount;
++ }
++
++ /**
+ * @return the errorLogfileSize
+ */
+ public int getErrorLogfileSize()
+@@ -708,8 +741,7 @@
}
catch (RepositoryException e)
{
@@ -21,7 +80,7 @@
}
return doc;
}
-@@ -736,8 +737,7 @@
+@@ -736,8 +768,7 @@
}
catch (RepositoryException e)
{
@@ -31,7 +90,7 @@
}
return null;
}
-@@ -870,25 +870,45 @@
+@@ -870,25 +901,45 @@
Sort sort = new Sort(createSortFields(orderProps, orderSpecs));
@@ -40,7 +99,7 @@
- searcher.setSimilarity(getSimilarity());
- return new FilterMultiColumnQueryHits(searcher.execute(query, sort, resultFetchHint,
- QueryImpl.DEFAULT_SELECTOR_NAME))
-+ for (int i = 0; i < IOEXCEPTION_RETRY_COUNT; i++)
++ for (int i = 0; i < ioExceptionRetryCount; i++)
{
- public void close() throws IOException
+ final IndexReader reader = getIndexReader(queryImpl.needsSystemTree());
@@ -77,18 +136,18 @@
{
- PerQueryCache.getInstance().dispose();
- Util.closeOrRelease(reader);
-+ log.error("Error occured while closing or releasing a reader" + releaseException);
++ log.warn("Error occured while closing or releasing a reader", releaseException);
}
}
- };
+ }
+
-+ throw new IOException("IO exception was encountered more than" + IOEXCEPTION_RETRY_COUNT + " times");
++ throw new IOException("IO exception was encountered more than " + ioExceptionRetryCount + " times");
+
}
/**
-@@ -918,24 +938,43 @@
+@@ -918,24 +969,43 @@
Sort sort = new Sort(createSortFields(orderProps, orderSpecs));
@@ -96,7 +155,7 @@
- JcrIndexSearcher searcher = new JcrIndexSearcher(session, reader, getContext().getItemStateManager());
- searcher.setSimilarity(getSimilarity());
- return new FilterMultiColumnQueryHits(query.execute(searcher, sort, resultFetchHint))
-+ for (int i = 0; i < IOEXCEPTION_RETRY_COUNT; i++)
++ for (int i = 0; i < ioExceptionRetryCount; i++)
{
- public void close() throws IOException
+ final IndexReader reader = getIndexReader();
@@ -132,17 +191,17 @@
{
- PerQueryCache.getInstance().dispose();
- Util.closeOrRelease(reader);
-+ log.error("Error occured while closing or releasing a reader" + releaseException);
++ log.warn("Error occured while closing or releasing a reader", releaseException);
}
}
- };
+ }
+
-+ throw new IOException("IO exception was encountered more than" + IOEXCEPTION_RETRY_COUNT + " times");
++ throw new IOException("IO exception was encountered more than " + ioExceptionRetryCount + " times");
}
/**
-@@ -1330,8 +1369,8 @@
+@@ -1330,8 +1400,8 @@
{
File root = new File(path, synonymProviderConfigPath.substring(0, lastSeparator));
fsr =
@@ -153,7 +212,7 @@
}
else
{
-@@ -1540,8 +1579,7 @@
+@@ -1540,8 +1610,7 @@
catch (Exception e)
{
// do not fail if aggregate cannot be created
@@ -163,7 +222,7 @@
}
}
}
-@@ -2712,11 +2750,32 @@
+@@ -2712,11 +2781,32 @@
{
checkOpen();
@@ -173,7 +232,7 @@
+ IndexReader reader;
- return new LuceneQueryHits(reader, searcher, query);
-+ for (int i = 0; i < IOEXCEPTION_RETRY_COUNT; i++)
++ for (int i = 0; i < ioExceptionRetryCount; i++)
+ {
+ reader = getIndexReader(true);
+ try
@@ -191,12 +250,24 @@
+ }
+ catch (Exception releaseException)
+ {
-+ log.error("Error occured while closing or releasing a reader" + releaseException);
++ log.warn("Error occured while closing or releasing a reader", releaseException);
+ }
+ }
+ }
+
-+ throw new IOException("IO exception was encountered more than" + IOEXCEPTION_RETRY_COUNT + " times");
++ throw new IOException("IO exception was encountered more than " + ioExceptionRetryCount + " times");
}
/**
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java (revision 3973)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java (working copy)
+@@ -114,4 +114,7 @@
+ public static final String PARAM_JBOSSCACHE_PUSHSTATE = "jbosscache-sscl-push.state.enabled";
+
+ public static final String PARAM_JBOSSCACHE_PUSHSTATE_TIMEOUT = "jbosscache-sscl-push.state.timeout";
++
++ public static final String PARAM_IO_EXCEPTION_RETRY_COUNT = "io-exception-retry-count";
++
+ }
13 years, 3 months