You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2009/11/25 15:04:50 UTC
svn commit: r884108 [2/10] - in /jackrabbit/sandbox/JCR-1456: ./
jackrabbit-api/
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/
jackrabbit-core/ jackrabbit-core/src...
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Wed Nov 25 14:04:38 2009
@@ -77,6 +77,7 @@
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
import org.apache.jackrabbit.core.query.QueryManagerImpl;
import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.AccessManager;
import org.apache.jackrabbit.core.state.ChildNodeEntry;
import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.core.state.ItemStateException;
@@ -520,16 +521,14 @@
thisState.addChildNodeEntry(name, nodeState.getNodeId());
// add 'auto-create' properties defined in node type
- PropertyDefinition[] pda = nodeType.getAutoCreatedPropertyDefinitions();
- for (int i = 0; i < pda.length; i++) {
- PropertyDefinitionImpl pd = (PropertyDefinitionImpl) pda[i];
+ for (PropertyDefinition aPda : nodeType.getAutoCreatedPropertyDefinitions()) {
+ PropertyDefinitionImpl pd = (PropertyDefinitionImpl) aPda;
node.createChildProperty(pd.unwrap().getName(), pd.getRequiredType(), pd);
}
// recursively add 'auto-create' child nodes defined in node type
- NodeDefinition[] nda = nodeType.getAutoCreatedNodeDefinitions();
- for (int i = 0; i < nda.length; i++) {
- NodeDefinitionImpl nd = (NodeDefinitionImpl) nda[i];
+ for (NodeDefinition aNda : nodeType.getAutoCreatedNodeDefinitions()) {
+ NodeDefinitionImpl nd = (NodeDefinitionImpl) aNda;
node.createChildNode(nd.unwrap().getName(), (NodeTypeImpl) nd.getDefaultPrimaryType(), null);
}
@@ -918,9 +917,8 @@
setMixinTypesProperty(mixins);
// add 'auto-create' properties defined in mixin type
- PropertyDefinition[] pda = mixin.getAutoCreatedPropertyDefinitions();
- for (int i = 0; i < pda.length; i++) {
- PropertyDefinitionImpl pd = (PropertyDefinitionImpl) pda[i];
+ for (PropertyDefinition aPda : mixin.getAutoCreatedPropertyDefinitions()) {
+ PropertyDefinitionImpl pd = (PropertyDefinitionImpl) aPda;
// make sure that the property is not already defined by primary type
// or existing mixin's
NodeTypeImpl declaringNT = (NodeTypeImpl) pd.getDeclaringNodeType();
@@ -930,9 +928,8 @@
}
// recursively add 'auto-create' child nodes defined in mixin type
- NodeDefinition[] nda = mixin.getAutoCreatedNodeDefinitions();
- for (int i = 0; i < nda.length; i++) {
- NodeDefinitionImpl nd = (NodeDefinitionImpl) nda[i];
+ for (NodeDefinition aNda : mixin.getAutoCreatedNodeDefinitions()) {
+ NodeDefinitionImpl nd = (NodeDefinitionImpl) aNda;
// make sure that the child node is not already defined by primary type
// or existing mixin's
NodeTypeImpl declaringNT = (NodeTypeImpl) nd.getDeclaringNodeType();
@@ -1663,6 +1660,7 @@
throw new ItemNotFoundException(
this + " has no child node with name " + name);
}
+
if (dstName != null && !hasNode(dstName.getName(), dstName.getIndex())) {
String name;
try {
@@ -1682,6 +1680,23 @@
| ItemValidator.CHECK_CONSTRAINTS;
session.getValidator().checkModify(this, options, Permission.NONE);
+ /*
+ make sure the session is allowed to reorder child nodes.
+ since there is no specific privilege for reordering child nodes,
+ test if the the node to be reordered can be removed and added,
+ i.e. treating reorder similar to a move.
+ TODO: properly deal with sns in which case the index would change upon reorder.
+ */
+ AccessManager acMgr = session.getAccessManager();
+ PathBuilder pb = new PathBuilder(getPrimaryPath());
+ pb.addLast(srcName.getName(), srcName.getIndex());
+ Path childPath = pb.getPath();
+ if (!acMgr.isGranted(childPath, Permission.ADD_NODE | Permission.REMOVE_NODE)) {
+ String msg = "Not allowed to reorder child node " + session.getJCRPath(childPath) + ".";
+ log.debug(msg);
+ throw new AccessDeniedException(msg);
+ }
+
ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(data.getNodeState().getChildNodeEntries());
int srcInd = -1, destInd = -1;
for (int i = 0; i < list.size(); i++) {
@@ -1786,8 +1801,8 @@
// create new child node
NodeImpl node = addNode(nodeName, nodeTypeName, id);
if (mixinNames != null) {
- for (int i = 0; i < mixinNames.length; i++) {
- node.addMixin(mixinNames[i]);
+ for (Name mixinName : mixinNames) {
+ node.addMixin(mixinName);
}
}
@@ -3409,7 +3424,7 @@
if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
return PropertyIteratorAdapter.EMPTY;
}
-
+
try {
StringBuilder stmt = new StringBuilder();
stmt.append("//*[@").append(ISO9075.encode(name));
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java Wed Nov 25 14:04:38 2009
@@ -27,6 +27,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.core.lock.LockManagerImpl;
import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
import org.apache.jackrabbit.core.persistence.PersistenceCopier;
@@ -262,12 +263,18 @@
target.createWorkspace(name);
}
+ // Copy all the workspace content
PersistenceCopier copier = new PersistenceCopier(
source.getWorkspaceInfo(name).getPersistenceManager(),
target.getWorkspaceInfo(name).getPersistenceManager(),
target.getDataStore());
copier.excludeNode(RepositoryImpl.SYSTEM_ROOT_NODE_ID);
copier.copy(RepositoryImpl.ROOT_NODE_ID);
+
+ // Copy all the active open-scoped locks
+ LockManagerImpl sourceLockManager = source.getLockManager(name);
+ LockManagerImpl targetLockManager = target.getLockManager(name);
+ targetLockManager.copyOpenScopedLocksFrom(sourceLockManager);
}
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Wed Nov 25 14:04:38 2009
@@ -19,7 +19,6 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
@@ -33,7 +32,6 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;
-import java.util.Iterator;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@@ -383,8 +381,15 @@
throw e;
} finally {
if (!succeeded) {
- // repository startup failed, clean up...
- shutdown();
+ try {
+ // repository startup failed, clean up...
+ shutdown();
+ } catch (Throwable t) {
+ // ensure this exception does not overlay the original
+ // startup exception and only log it
+ log.error("In addition to startup fail, another unexpected problem " +
+ "occurred while shutting down the repository again.", t);
+ }
}
}
}
@@ -448,7 +453,7 @@
log.debug("No configuration entry for SecurityManager. Using org.apache.jackrabbit.core.security.simple.SimpleSecurityManager");
securityMgr = new SimpleSecurityManager();
} else {
- securityMgr = (JackrabbitSecurityManager) smc.newInstance();
+ securityMgr = smc.newInstance(JackrabbitSecurityManager.class);
}
securityMgr.init(this, securitySession);
@@ -916,7 +921,7 @@
* @throws NoSuchWorkspaceException if such a workspace does not exist
* @throws RepositoryException if some other error occurs
*/
- LockManager getLockManager(String workspaceName) throws
+ LockManagerImpl getLockManager(String workspaceName) throws
NoSuchWorkspaceException, RepositoryException {
// check sanity of this instance
sanityCheck();
@@ -1065,7 +1070,7 @@
} else {
log.debug("Found preauthenticated Subject, try to extend authentication");
// login either using JAAS or custom LoginModule
- AuthContext authCtx = getSecurityManager().getAuthContext(null, subject);
+ AuthContext authCtx = getSecurityManager().getAuthContext(null, subject, workspaceName);
try {
authCtx.login();
s = createSession(authCtx, workspaceName);
@@ -1322,8 +1327,8 @@
// now set customized repository descriptor values (if any exist)
Properties props = getCustomRepositoryDescriptors();
if (props != null) {
- for (Iterator it = props.keySet().iterator(); it.hasNext();) {
- String key = (String) it.next();
+ for (Object o : props.keySet()) {
+ String key = (String) o;
setDescriptor(key, props.getProperty(key));
}
}
@@ -1396,7 +1401,7 @@
DataStore dataStore)
throws RepositoryException {
try {
- PersistenceManager pm = (PersistenceManager) pmConfig.newInstance();
+ PersistenceManager pm = pmConfig.newInstance(PersistenceManager.class);
pm.init(new PMContext(homeDir, fs, rootNodeId, nsReg, ntReg, dataStore));
return pm;
} catch (Exception e) {
@@ -1464,16 +1469,15 @@
}
}
// not preauthenticated -> try login with credentials
- AuthContext authCtx = getSecurityManager().getAuthContext(credentials, new Subject());
+ AuthContext authCtx = getSecurityManager().getAuthContext(credentials, new Subject(), workspaceName);
authCtx.login();
// create session, and add SimpleCredentials attributes (JCR-1932)
SessionImpl session = createSession(authCtx, workspaceName);
if (credentials instanceof SimpleCredentials) {
SimpleCredentials sc = (SimpleCredentials) credentials;
- String[] names = sc.getAttributeNames();
- for (int i = 0; i < names.length; i++) {
- session.setAttribute(names[i], sc.getAttribute(names[i]));
+ for (String name : sc.getAttributeNames()) {
+ session.setAttribute(name, sc.getAttribute(name));
}
}
return session;
@@ -1852,7 +1856,7 @@
* @return the lock manager for this workspace
* @throws RepositoryException if the lock manager could not be created
*/
- protected LockManager getLockManager() throws RepositoryException {
+ protected LockManagerImpl getLockManager() throws RepositoryException {
if (!isInitialized()) {
throw new IllegalStateException("workspace '" + getName()
+ "' not initialized");
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Wed Nov 25 14:04:38 2009
@@ -50,8 +50,6 @@
import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
import org.apache.jackrabbit.core.xml.ImportHandler;
import org.apache.jackrabbit.core.xml.SessionImporter;
-import org.apache.jackrabbit.core.xml.AccessControlImporter;
-import org.apache.jackrabbit.core.xml.ProtectedNodeImporter;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
@@ -86,7 +84,6 @@
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.ValueFactory;
import javax.jcr.Workspace;
-import javax.jcr.ImportUUIDBehavior;
import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
@@ -280,7 +277,7 @@
this.rep = rep;
this.subject = subject;
- userId = retrieveUserId(subject);
+ userId = retrieveUserId(subject, wspConfig.getName());
namePathResolver = new DefaultNamePathResolver(this, this, true);
ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), this, rep.getDataStore());
@@ -300,8 +297,8 @@
*
* @return the userID.
*/
- protected String retrieveUserId(Subject subject) throws RepositoryException {
- return rep.getSecurityManager().getUserID(subject);
+ protected String retrieveUserId(Subject subject, String workspaceName) throws RepositoryException {
+ return rep.getSecurityManager().getUserID(subject, workspaceName);
}
/**
@@ -1166,9 +1163,7 @@
ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
getValidator().checkModify(parent, options, Permission.NONE);
- // TODO: make configurable
- ProtectedNodeImporter pi = new AccessControlImporter(this, this, false, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
- SessionImporter importer = new SessionImporter(parent, this, uuidBehavior, pi, null);
+ SessionImporter importer = new SessionImporter(parent, this, uuidBehavior, wsp.getConfig().getImportConfig());
return new ImportHandler(importer, this);
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java Wed Nov 25 14:04:38 2009
@@ -81,7 +81,7 @@
*
* @return the name of <code>SystemPrincipal</code>.
*/
- protected String retrieveUserId(Subject subject) throws RepositoryException {
+ protected String retrieveUserId(Subject subject, String workspaceName) throws RepositoryException {
return new SystemPrincipal().getName();
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java Wed Nov 25 14:04:38 2009
@@ -835,7 +835,7 @@
}
Importer importer = new WorkspaceImporter(parentPath, this,
- rep.getNodeTypeRegistry(), uuidBehavior);
+ rep.getNodeTypeRegistry(), uuidBehavior, wspConfig.getImportConfig());
return new ImportHandler(importer, session);
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java Wed Nov 25 14:04:38 2009
@@ -16,25 +16,28 @@
*/
package org.apache.jackrabbit.core.config;
-import org.apache.commons.collections.BeanMap;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
import org.apache.jackrabbit.core.util.db.ConnectionFactory;
import org.apache.jackrabbit.core.util.db.DatabaseAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Properties;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Collections;
-import java.io.InputStream;
-import java.io.IOException;
-
/**
* Bean configuration class. BeanConfig instances contain the class name
* and property information required to instantiate a class that conforms
* with the JavaBean conventions.
*/
-public class BeanConfig<T> {
+public class BeanConfig {
private static Logger log = LoggerFactory.getLogger(BeanConfig.class);
@@ -167,42 +170,42 @@
* @return new bean instance
* @throws ConfigurationException on bean configuration errors
*/
- public Object newInstance() throws ConfigurationException {
+ @SuppressWarnings("unchecked")
+ public <T> T newInstance(Class<T> klass) throws ConfigurationException {
try {
- // Instantiate the object using the default constructor
Class<?> objectClass =
Class.forName(getClassName(), true, getClassLoader());
- Object object = objectClass.newInstance();
+ if (!klass.isAssignableFrom(objectClass)) {
+ throw new ConfigurationException(
+ "Configured class "+getClassName()
+ + " does not implement " + klass.getName()
+ + ". Please fix the repository configuration.");
+ }
+
+ // Instantiate the object using the default constructor
+ Object instance = objectClass.newInstance();
// Set all configured bean properties
- BeanMap map = new BeanMap(object);
- for (Object key : map.keySet()) {
- String value = properties.getProperty(key.toString());
- if (value != null) {
- map.put(key, value);
+ Map<String, Method> setters = getSetters(objectClass);
+ Enumeration<?> enumeration = properties.propertyNames();
+ while (enumeration.hasMoreElements()) {
+ String name = enumeration.nextElement().toString();
+ Method setter = setters.get(name);
+ if (setter != null) {
+ String value = properties.getProperty(name);
+ setProperty(instance, name, setter, value);
+ } else if (validate) {
+ throw new ConfigurationException(
+ "Configured class " + getClassName()
+ + " does not contain a property named " + name);
}
}
- if (object instanceof DatabaseAware) {
- ((DatabaseAware) object).setConnectionFactory(connectionFactory);
+ if (instance instanceof DatabaseAware) {
+ ((DatabaseAware) instance).setConnectionFactory(connectionFactory);
}
- if (validate) {
- // Check that no invalid property names were configured
- for (Object key : properties.keySet()) {
- if (!map.containsKey(key)
- && properties.getProperty(key.toString()) != null) {
- String msg =
- "Configured class " + object.getClass().getName()
- + " does not contain the property " + key
- + ". Please fix the repository configuration.";
- log.error(msg);
- throw new ConfigurationException(msg);
- }
- }
- }
-
- return (T) object;
+ return (T) instance;
} catch (ClassNotFoundException e) {
throw new ConfigurationException(
"Configured bean implementation class " + getClassName()
@@ -218,6 +221,70 @@
}
}
+ private Map<String, Method> getSetters(Class<?> klass) {
+ Map<String, Method> methods = new HashMap<String, Method>();
+ for (Method method : klass.getMethods()) {
+ String name = method.getName();
+ if (name.startsWith("set") && name.length() > 3
+ && Modifier.isPublic(method.getModifiers())
+ && !Modifier.isStatic(method.getModifiers())
+ && Void.TYPE.equals(method.getReturnType())
+ && method.getParameterTypes().length == 1) {
+ methods.put(
+ name.substring(3, 4).toLowerCase() + name.substring(4),
+ method);
+ }
+ }
+ return methods;
+ }
+
+ private void setProperty(
+ Object instance, String name, Method setter, String value)
+ throws ConfigurationException {
+ Class<?> type = setter.getParameterTypes()[0];
+ try {
+ if (type.isAssignableFrom(String.class)
+ || type.isAssignableFrom(Object.class)) {
+ setter.invoke(instance, value);
+ } else if (type.isAssignableFrom(Boolean.TYPE)
+ || type.isAssignableFrom(Boolean.class)) {
+ setter.invoke(instance, Boolean.valueOf(value));
+ } else if (type.isAssignableFrom(Integer.TYPE)
+ || type.isAssignableFrom(Integer.class)) {
+ setter.invoke(instance, Integer.valueOf(value));
+ } else if (type.isAssignableFrom(Long.TYPE)
+ || type.isAssignableFrom(Long.class)) {
+ setter.invoke(instance, Long.valueOf(value));
+ } else if (type.isAssignableFrom(Double.TYPE)
+ || type.isAssignableFrom(Double.class)) {
+ setter.invoke(instance, Double.valueOf(value));
+ } else {
+ throw new ConfigurationException(
+ "The type (" + type.getName()
+ + ") of property " + name + " of class "
+ + getClassName() + " is not supported");
+ }
+ } catch (NumberFormatException e) {
+ throw new ConfigurationException(
+ "Invalid number format (" + value + ") for property "
+ + name + " of class " + getClassName(), e);
+ } catch (InvocationTargetException e) {
+ throw new ConfigurationException(
+ "Property " + name + " of class "
+ + getClassName() + " can not be set to \"" + value + "\"",
+ e);
+ } catch (IllegalAccessException e) {
+ throw new ConfigurationException(
+ "The setter of property " + name
+ + " of class " + getClassName() + " can not be accessed",
+ e);
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException(
+ "Unable to call the setter of property "
+ + name + " of class " + getClassName(), e);
+ }
+ }
+
//---------- Configurable class loader support ----------------------------
/**
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/LoginModuleConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/LoginModuleConfig.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/LoginModuleConfig.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/LoginModuleConfig.java Wed Nov 25 14:04:38 2009
@@ -60,12 +60,6 @@
}
public LoginModule getLoginModule() throws ConfigurationException {
- Object result = newInstance();
- if (result instanceof LoginModule) {
- return (LoginModule) result;
- } else {
- throw new ConfigurationException("Invalid login module implementation class "
- + getClassName() + ".");
- }
+ return newInstance(LoginModule.class);
}
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java Wed Nov 25 14:04:38 2009
@@ -47,6 +47,8 @@
import java.io.IOException;
import java.util.Properties;
import java.util.UUID;
+import java.util.List;
+import java.util.ArrayList;
import javax.jcr.RepositoryException;
@@ -193,6 +195,19 @@
private final ConnectionFactory connectionFactory;
/**
+ * Element specifying the class of principals used to retrieve the userID
+ * in the 'class' attribute.
+ */
+ private static final String USERID_CLASS = "UserIdClass";
+
+ /**
+ * Name of the optional XmlImport config entry inside the workspace configuration.
+ */
+ private static final String IMPORT_ELEMENT = "Import";
+ private static final String IMPORT_PNI_ELEMENT = "ProtectedNodeImporter";
+ private static final String IMPORT_PPI_ELEMENT = "ProtectedPropertyImporter";
+
+ /**
* Name of the cluster node id file.
*/
private static final String CLUSTER_NODE_ID_FILE = "cluster_node.id";
@@ -385,12 +400,19 @@
wac = parseBeanConfig(smElement, WORKSPACE_ACCESS_ELEMENT);
}
- BeanConfig umc = null;
+ UserManagerConfig umc = null;
element = getElement(smElement, USER_MANAGER_ELEMENT, false);
if (element != null) {
- umc = parseBeanConfig(smElement, USER_MANAGER_ELEMENT);
+ umc = new UserManagerConfig(parseBeanConfig(smElement, USER_MANAGER_ELEMENT));
}
- return new SecurityManagerConfig(bc, wspAttr, wac, umc);
+
+ BeanConfig uidcc = null;
+ element = getElement(smElement, USERID_CLASS, false);
+ if (element != null) {
+ uidcc = parseBeanConfig(element);
+ }
+
+ return new SecurityManagerConfig(bc, wspAttr, wac, umc, uidcc);
} else {
return null;
}
@@ -480,7 +502,6 @@
* @return workspace configuration
* @throws ConfigurationException if the configuration is broken
* @see #parseBeanConfig(Element, String)
- * @see #parseSearchConfig(Element)
* @see #parseWorkspaceSecurityConfig(Element)
*/
public WorkspaceConfig parseWorkspaceConfig(InputSource xml)
@@ -509,7 +530,7 @@
// Clustered attribute
boolean clustered = Boolean.valueOf(
- getAttribute(root, CLUSTERED_ATTRIBUTE, "true")).booleanValue();
+ getAttribute(root, CLUSTERED_ATTRIBUTE, "true"));
// Create a temporary parser that contains the ${wsp.name} variable
Properties tmpVariables = (Properties) getVariables().clone();
@@ -533,9 +554,12 @@
// workspace specific security configuration
WorkspaceSecurityConfig workspaceSecurityConfig = tmpParser.parseWorkspaceSecurityConfig(root);
+ // optinal config for import handling
+ ImportConfig importConfig = tmpParser.parseImportConfig(root);
+
return new WorkspaceConfig(
home, name, clustered, fsf, pmc, qhf,
- ismLockingFactory, workspaceSecurityConfig);
+ ismLockingFactory, workspaceSecurityConfig, importConfig);
}
/**
@@ -589,7 +613,7 @@
className, parseParameters(element));
QueryHandler handler =
- (QueryHandler) config.newInstance();
+ config.newInstance(QueryHandler.class);
try {
handler.init(fs, context);
return handler;
@@ -634,6 +658,49 @@
}
/**
+ * Read the optional XmlImport Element of Workspace's configuration. It uses
+ * the following format:
+ * <pre>
+ * <XmlImport>
+ * <ProtectedNodeImporter class="..." (optional)>
+ * <ProtectedNodeImporter class="..." (optional)>
+ * ...
+ * <ProtectedPropertyImporter class="..." (optional)>
+ * </XmlImport>
+ * </pre>
+ *
+ * @param parent Workspace-Root-Element
+ * @return a new <code>XmlImportConfig</code>
+ * @throws ConfigurationException
+ */
+ public ImportConfig parseImportConfig(Element parent) throws ConfigurationException {
+ List<BeanConfig> protectedNodeImporters = new ArrayList();
+ List<BeanConfig> protectedPropertyImporters = new ArrayList();
+
+ Element element = getElement(parent, IMPORT_ELEMENT, false);
+ if (element != null) {
+ NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ if (IMPORT_PNI_ELEMENT.equals(child.getNodeName())) {
+ String className = getAttribute((Element) child, CLASS_ATTRIBUTE);
+ BeanConfig bc = new BeanConfig(className, parseParameters((Element) child));
+ bc.setValidate(false);
+ protectedNodeImporters.add(bc);
+ } else if (IMPORT_PPI_ELEMENT.equals(child.getNodeName())) {
+ String className = getAttribute((Element) child, CLASS_ATTRIBUTE);
+ BeanConfig bc = new BeanConfig(className, parseParameters((Element) child));
+ bc.setValidate(false);
+ protectedPropertyImporters.add(bc);
+ } // else: some other entry -> ignore.
+ }
+ }
+ }
+ return new ImportConfig(protectedNodeImporters, protectedPropertyImporters);
+ }
+
+ /**
* Returns an ISM locking factory that creates {@link ISMLocking} instances
* based on the given configuration. ISM locking configuration uses the
* following format:
@@ -659,14 +726,7 @@
public ISMLocking getISMLocking() throws RepositoryException {
Element element = getElement(parent, ISM_LOCKING_ELEMENT, false);
if (element != null) {
- BeanConfig config = parseBeanConfig(element);
- try {
- return (ISMLocking) config.newInstance();
- } catch (ClassCastException e) {
- throw new RepositoryException(
- "Invalid ISMLocking class: "
- + config.getClassName(), e);
- }
+ return parseBeanConfig(element).newInstance(ISMLocking.class);
} else {
return new DefaultISMLocking();
}
@@ -801,25 +861,18 @@
public Journal getJournal(NamespaceResolver resolver)
throws RepositoryException {
BeanConfig config = parseBeanConfig(cluster, JOURNAL_ELEMENT);
- Object object = config.newInstance();
- if (object instanceof Journal) {
- Journal journal = (Journal) object;
- if (journal instanceof AbstractJournal) {
- ((AbstractJournal) journal).setRepositoryHome(home);
- }
- try {
- journal.init(id, resolver);
- } catch (JournalException e) {
- // TODO: Should JournalException extend RepositoryException?
- throw new RepositoryException(
- "Journal initialization failed: " + journal, e);
- }
- return journal;
- } else {
+ Journal journal = config.newInstance(Journal.class);
+ if (journal instanceof AbstractJournal) {
+ ((AbstractJournal) journal).setRepositoryHome(home);
+ }
+ try {
+ journal.init(id, resolver);
+ } catch (JournalException e) {
+ // TODO: Should JournalException extend RepositoryException?
throw new RepositoryException(
- "Invalid Journal implementation class: "
- + config.getClassName());
+ "Journal initialization failed: " + journal, e);
}
+ return journal;
}
};
}
@@ -885,7 +938,7 @@
&& DATA_STORE_ELEMENT.equals(child.getNodeName())) {
BeanConfig bc =
parseBeanConfig(parent, DATA_STORE_ELEMENT);
- DataStore store = (DataStore) bc.newInstance();
+ DataStore store = bc.newInstance(DataStore.class);
store.init(directory);
return store;
}
@@ -915,7 +968,6 @@
protected RepositoryLockMechanismFactory getRepositoryLockMechanismFactory(final Element root) {
return new RepositoryLockMechanismFactory() {
public RepositoryLockMechanism getRepositoryLockMechanism() throws RepositoryException {
- RepositoryLockMechanism lock = null;
NodeList children = root.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
@@ -923,14 +975,10 @@
&& REPOSITORY_LOCK_MECHANISM_ELEMENT.equals(child.getNodeName())) {
BeanConfig bc =
parseBeanConfig(root, REPOSITORY_LOCK_MECHANISM_ELEMENT);
- lock = (RepositoryLockMechanism) bc.newInstance();
- break;
+ return bc.newInstance(RepositoryLockMechanism.class);
}
}
- if (lock == null) {
- lock = new RepositoryLock();
- }
- return lock;
+ return new RepositoryLock();
}
};
}
@@ -977,13 +1025,9 @@
return new FileSystemFactory() {
public FileSystem getFileSystem() throws RepositoryException {
try {
- FileSystem fs = (FileSystem) config.newInstance();
+ FileSystem fs = config.newInstance(FileSystem.class);
fs.init();
return fs;
- } catch (ClassCastException e) {
- throw new RepositoryException(
- "Invalid file system implementation class: "
- + config.getClassName(), e);
} catch (FileSystemException e) {
throw new RepositoryException(
"File system initialization failure.", e);
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SecurityManagerConfig.java Wed Nov 25 14:04:38 2009
@@ -16,6 +16,9 @@
*/
package org.apache.jackrabbit.core.config;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Security manager configuration. This bean configuration class
* is used to create configured security manager objects.
@@ -27,9 +30,19 @@
*/
public class SecurityManagerConfig extends BeanConfig {
+ /**
+ * the default logger
+ */
+ private static final Logger log = LoggerFactory.getLogger(SecurityManagerConfig.class);
+
private final String workspaceName;
private final BeanConfig workspaceAccessConfig;
- private final BeanConfig userManagerConfig;
+ private final UserManagerConfig userManagerConfig;
+
+ /**
+ * Optional class used to retrieve userID from the subject.
+ */
+ private final Class uidClass;
/**
* Creates an security manager configuration object from the
@@ -41,7 +54,7 @@
*/
public SecurityManagerConfig(BeanConfig config, String workspaceName,
BeanConfig workspaceAccessConfig) {
- this(config, workspaceName, workspaceAccessConfig, null);
+ this(config, workspaceName, workspaceAccessConfig, null, null);
}
/**
@@ -55,11 +68,21 @@
*/
public SecurityManagerConfig(BeanConfig config, String workspaceName,
BeanConfig workspaceAccessConfig,
- BeanConfig userManagerConfig) {
+ UserManagerConfig userManagerConfig,
+ BeanConfig uidClassConfig) {
super(config);
this.workspaceName = workspaceName;
this.workspaceAccessConfig = workspaceAccessConfig;
this.userManagerConfig = userManagerConfig;
+ Class cl = null;
+ if (uidClassConfig != null) {
+ try {
+ cl = Class.forName(uidClassConfig.getClassName(), true, uidClassConfig.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ log.error("Configured bean implementation class " + uidClassConfig.getClassName() + " was not found -> Ignoring UserIdClass element.", e);
+ }
+ }
+ this.uidClass = cl;
}
/**
@@ -86,7 +109,16 @@
* May be <code>null</code> if the configuration entry is missing (i.e.
* the system default should be used).
*/
- public BeanConfig getUserManagerConfig() {
+ public UserManagerConfig getUserManagerConfig() {
return userManagerConfig;
}
+
+ /**
+ * @return Class which is used to retrieve the UserID from the Subject.
+ * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#getUserID(javax.security.auth.Subject, String)
+ * @see javax.security.auth.Subject#getPrincipals(Class)
+ */
+ public Class getUserIdClass() {
+ return uidClass;
+ }
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java Wed Nov 25 14:04:38 2009
@@ -79,6 +79,15 @@
private final WorkspaceSecurityConfig workspaceSecurityConfig;
/**
+ * Optional configuration for the xml import behavior. Up to now this consists
+ * of a single configuration point: the treatment
+ * of protected nodes and properties that is defined by a set of classes
+ * implementing {@link org.apache.jackrabbit.core.xml.ProtectedNodeImporter}
+ * or {@link org.apache.jackrabbit.core.xml.ProtectedPropertyImporter}.
+ */
+ private final ImportConfig importConfig;
+
+ /**
* Creates a workspace configuration object.
*
* @param home home directory
@@ -95,6 +104,27 @@
QueryHandlerFactory qhf,
ISMLockingFactory ismLockingFactory,
WorkspaceSecurityConfig workspaceSecurityConfig) {
+ this(home, name, clustered, fsf, pmc, qhf, ismLockingFactory, workspaceSecurityConfig, null);
+ }
+
+ /**
+ * Creates a workspace configuration object.
+ *
+ * @param home home directory
+ * @param name workspace name
+ * @param clustered
+ * @param fsf file system factory
+ * @param pmc persistence manager configuration
+ * @param qhf query handler factory, or <code>null</code> if not configured
+ * @param ismLockingFactory the item state manager locking factory
+ * @param workspaceSecurityConfig the workspace specific security configuration.
+ */
+ public WorkspaceConfig(String home, String name, boolean clustered,
+ FileSystemFactory fsf, PersistenceManagerConfig pmc,
+ QueryHandlerFactory qhf,
+ ISMLockingFactory ismLockingFactory,
+ WorkspaceSecurityConfig workspaceSecurityConfig,
+ ImportConfig importConfig) {
this.home = home;
this.name = name;
this.clustered = clustered;
@@ -103,6 +133,7 @@
this.qhf = qhf;
this.ismLockingFactory = ismLockingFactory;
this.workspaceSecurityConfig = workspaceSecurityConfig;
+ this.importConfig = importConfig;
}
/**
@@ -193,4 +224,11 @@
public WorkspaceSecurityConfig getSecurityConfig() {
return workspaceSecurityConfig;
}
+
+ /**
+ * @return xml import settings
+ */
+ public ImportConfig getImportConfig() {
+ return importConfig;
+ }
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java Wed Nov 25 14:04:38 2009
@@ -30,6 +30,11 @@
private static final long serialVersionUID = 5773949574212570258L;
/**
+ * Chars in a UUID String.
+ */
+ public static final int UUID_FORMATTED_LENGTH = 36;
+
+ /**
* Number of bytes in a UUID (16).
*/
public static final int UUID_BYTE_LENGTH = 16;
@@ -113,12 +118,12 @@
/**
* Creates a node identifier from the given UUID string.
*
- * @see UUID#fromString(String)
+ * @see #fromString(String)
* @param uuid UUID string
* @throws IllegalArgumentException if the UUID string is invalid
*/
public NodeId(String uuid) throws IllegalArgumentException {
- this(UUID.fromString(uuid));
+ this(fromString(uuid));
}
/**
@@ -241,4 +246,47 @@
return (int) ((msb >>> 32) ^ msb ^ (lsb >>> 32) ^ lsb);
}
+ //------------------------------------------------------------< internal >
+
+ /**
+ * Constructs a UUID from a UUID formatted String.
+ *
+ * @param uuidString the String representing a UUID to construct this UUID
+ * @return the UUID created from the given string.
+ * @throws IllegalArgumentException String must be a properly formatted UUID
+ * string
+ */
+ private static UUID fromString(String uuidString)
+ throws IllegalArgumentException {
+ // e.g. f81d4fae-7dec-11d0-a765-00a0c91e6bf6
+ // 012345678901234567890123456789012345
+ int len = uuidString.length();
+ if (len != UUID_FORMATTED_LENGTH) {
+ throw new IllegalArgumentException();
+ }
+ long[] words = new long[2];
+ int b = 0;
+ for (int i = 0; i < UUID_FORMATTED_LENGTH; i++) {
+ int c = uuidString.charAt(i) | 0x20; // to lowercase (will lose some error checking)
+ if (i == 8 || i == 13 || i == 23) {
+ if (c != '-') {
+ throw new IllegalArgumentException(String.valueOf(i));
+ }
+ } else if (i == 18) {
+ if (c != '-') {
+ throw new IllegalArgumentException(String.valueOf(i));
+ }
+ b = 1;
+ } else {
+ byte h = (byte) (c & 0x0f);
+ if (c >= 'a' && c <= 'f') {
+ h += 9;
+ } else if (c < '0' || c > '9') {
+ throw new IllegalArgumentException();
+ }
+ words[b] = words[b] << 4 | h;
+ }
+ }
+ return new UUID(words[0], words[1]);
+ }
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java Wed Nov 25 14:04:38 2009
@@ -490,6 +490,30 @@
}
/**
+ * Helper method that copies all the active open-scoped locks from the
+ * given source to this lock manager. This method is used when backing
+ * up repositories, and only works correctly when the source lock manager
+ * belongs to the original copy of the workspace being backed up.
+ *
+ * @see org.apache.jackrabbit.core.RepositoryCopier
+ * @param source source lock manager
+ */
+ public void copyOpenScopedLocksFrom(LockManagerImpl source) {
+ source.lockMap.traverse(new PathMap.ElementVisitor<LockInfo>() {
+ public void elementVisited(PathMap.Element<LockInfo> element) {
+ LockInfo info = element.get();
+ if (info.isLive() && !info.isSessionScoped()) {
+ try {
+ lockMap.put(element.getPath(), info);
+ } catch (MalformedPathException e) {
+ log.warn("Ignoring invalid lock path: " + info, e);
+ }
+ }
+ }
+ }, false);
+ }
+
+ /**
* Return the most appropriate lock information for a node. This is either
* the lock info for the node itself, if it is locked, or a lock info for one
* of its parents, if that is deep locked.
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java Wed Nov 25 14:04:38 2009
@@ -16,8 +16,21 @@
*/
package org.apache.jackrabbit.core.observation;
-import org.apache.jackrabbit.core.id.ItemId;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+
import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.id.ItemId;
import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.PathFactory;
@@ -25,18 +38,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-
/**
* The <code>EventConsumer</code> class combines the {@link
* javax.jcr.observation.EventListener} with the implementation of specified
@@ -241,7 +242,13 @@
EventIterator it = new FilteredEventIterator(events.iterator(),
events.getTimestamp(), events.getUserData(), filter, denied);
if (it.hasNext()) {
+ long time = System.currentTimeMillis();
listener.onEvent(it);
+ time = System.currentTimeMillis() - time;
+ if (log.isDebugEnabled()) {
+ log.debug("listener {} processed events in {} ms.",
+ listener.getClass().getName(), time);
+ }
} else {
// otherwise skip this listener
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/ObservationManagerImpl.java Wed Nov 25 14:04:38 2009
@@ -87,19 +87,22 @@
* belongs to.
* @param itemMgr {@link org.apache.jackrabbit.core.ItemManager} of the passed
* <code>Session</code>.
- * @throws NullPointerException if <code>session</code> or <code>itemMgr</code>
- * is <code>null</code>.
+ * @throws NullPointerException if <code>dispatcher</code>, <code>session</code>
+ * or <code>itemMgr</code> is <code>null</code>.
*/
public ObservationManagerImpl(
ObservationDispatcher dispatcher, SessionImpl session,
ItemManager itemMgr, ClusterNode clusterNode) {
+ if (dispatcher == null) {
+ throw new NullPointerException("dispatcher");
+ }
if (session == null) {
throw new NullPointerException("session");
}
if (itemMgr == null) {
throw new NullPointerException("itemMgr");
}
-
+
this.dispatcher = dispatcher;
this.session = session;
this.itemMgr = itemMgr;
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/SynchronousEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/SynchronousEventListener.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/SynchronousEventListener.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/SynchronousEventListener.java Wed Nov 25 14:04:38 2009
@@ -16,6 +16,7 @@
*/
package org.apache.jackrabbit.core.observation;
+import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
/**
@@ -25,6 +26,10 @@
* the call to {@link javax.jcr.Item#save()} returns. In contrast, a regular
* {@link javax.jcr.observation.EventListener} might be called after
* <code>save()</code> returns.
+ * <p/>
+ * <b>Important note</b>: an implementation of {@link SynchronousEventListener}
+ * <b>must not</b> modify content with the thread that calls {@link
+ * #onEvent(EventIterator)} otherwise inconsistencies may occur.
*/
public interface SynchronousEventListener extends EventListener {
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java Wed Nov 25 14:04:38 2009
@@ -393,8 +393,10 @@
val = InternalValue.create(readQName(in));
break;
case PropertyType.WEAKREFERENCE:
+ val = InternalValue.create(readID(in), true);
+ break;
case PropertyType.REFERENCE:
- val = InternalValue.create(readID(in));
+ val = InternalValue.create(readID(in), false);
break;
default:
// because writeUTF(String) has a size limit of 64k,
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java Wed Nov 25 14:04:38 2009
@@ -23,6 +23,7 @@
import org.apache.jackrabbit.core.fs.FileSystemPathUtil;
import org.apache.jackrabbit.core.fs.FileSystemResource;
import org.apache.jackrabbit.core.fs.local.LocalFileSystem;
+import org.apache.jackrabbit.core.fs.mem.MemoryFileSystem;
import org.apache.jackrabbit.core.persistence.AbstractPersistenceManager;
import org.apache.jackrabbit.core.persistence.PMContext;
import org.apache.jackrabbit.core.persistence.util.BLOBStore;
@@ -290,14 +291,14 @@
wspFS = context.getFileSystem();
- /**
- * store BLOB data in local file system in a sub directory
- * of the workspace home directory
- */
- LocalFileSystem blobFS = new LocalFileSystem();
- blobFS.setRoot(new File(context.getHomeDir(), "blobs"));
+ // Choose a FileSystem for the BlobStore based on whether data is persistent or not
+ if (persistent) {
+ blobFS = new LocalFileSystem();
+ ((LocalFileSystem) blobFS).setRoot(new File(context.getHomeDir(), "blobs"));
+ } else {
+ blobFS = new MemoryFileSystem();
+ }
blobFS.init();
- this.blobFS = blobFS;
blobStore = new FileSystemBLOBStore(blobFS);
if (persistent) {
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java Wed Nov 25 14:04:38 2009
@@ -152,4 +152,18 @@
public static int getNameLength(String namedValue) {
return namedValue.indexOf('[') + 1;
}
+
+ /**
+ * Returns <code>true</code> if the given <code>fieldName</code> denotes a
+ * fulltext field like {@link #FULLTEXT} or a field with a
+ * {@link #FULLTEXT_PREFIX}.
+ *
+ * @param fieldName a field name.
+ * @return <code>true</code> if <code>fieldName</code> is a fulltext field;
+ * <code>false</code> otherwise.
+ */
+ public static boolean isFulltextField(String fieldName) {
+ return fieldName.equals(FULLTEXT)
+ || fieldName.indexOf(FULLTEXT_PREFIX) != -1;
+ }
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexInfos.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexInfos.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexInfos.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexInfos.java Wed Nov 25 14:04:38 2009
@@ -16,21 +16,23 @@
*/
package org.apache.jackrabbit.core.query.lucene;
+import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.BufferedOutputStream;
import java.util.ArrayList;
-import java.util.List;
-import java.util.LinkedHashMap;
import java.util.Iterator;
-import java.util.NoSuchElementException;
+import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
-import org.apache.lucene.store.Directory;
import org.apache.jackrabbit.core.query.lucene.directory.IndexInputStream;
import org.apache.jackrabbit.core.query.lucene.directory.IndexOutputStream;
+import org.apache.lucene.store.Directory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -147,8 +149,8 @@
String newName = getFileName();
boolean success = false;
try {
- OutputStream out = new IndexOutputStream(
- directory.createOutput(newName));
+ OutputStream out = new BufferedOutputStream(new IndexOutputStream(
+ directory.createOutput(newName)));
try {
log.debug("Writing IndexInfos {}", newName);
DataOutputStream dataOut = new DataOutputStream(out);
@@ -288,7 +290,8 @@
*/
private void read() throws IOException {
String fileName = getFileName(generation);
- InputStream in = new IndexInputStream(directory.openInput(fileName));
+ InputStream in = new BufferedInputStream(new IndexInputStream(
+ directory.openInput(fileName)));
try {
LinkedHashMap<String, IndexInfo> indexes = new LinkedHashMap<String, IndexInfo>();
DataInputStream di = new DataInputStream(in);
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java Wed Nov 25 14:04:38 2009
@@ -16,20 +16,23 @@
*/
package org.apache.jackrabbit.core.query.lucene;
-import org.apache.lucene.index.Term;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.List;
-import java.util.Collections;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Semaphore;
-import java.io.IOException;
-
/**
* Merges indexes in a separate daemon thread.
*/
@@ -41,11 +44,6 @@
private static final Logger log = LoggerFactory.getLogger(IndexMerger.class);
/**
- * Marker task to signal the background thread to quit.
- */
- private static final Merge QUIT = new Merge(new Index[0]);
-
- /**
* minMergeDocs config parameter.
*/
private int minMergeDocs = SearchIndex.DEFAULT_MIN_MERGE_DOCS;
@@ -61,11 +59,6 @@
private int mergeFactor = SearchIndex.DEFAULT_MERGE_FACTOR;
/**
- * Queue of merge Tasks
- */
- private final BlockingQueue<Merge> mergeTasks = new LinkedBlockingQueue<Merge>();
-
- /**
* List of <code>IndexBucket</code>s in ascending document limit.
*/
private final List<IndexBucket> indexBuckets = new ArrayList<IndexBucket>();
@@ -76,14 +69,34 @@
private final MultiIndex multiIndex;
/**
+ * The executor of the repository.
+ */
+ private final Executor executor;
+
+ /**
+ * Flag that indicates that this index merger is shuting down and should
+ * quit.
+ */
+ private final AtomicBoolean quit = new AtomicBoolean(false);
+
+ /**
+ * Flag that indicates if this index merger has already been started.
+ * @see #start()
+ */
+ private final AtomicBoolean isStarted = new AtomicBoolean(false);
+
+ /**
* Monitor object to synchronize merge calculation.
*/
private final Object lock = new Object();
/**
- * Mutex that is acquired when replacing indexes on MultiIndex.
+ * Read/write lock for index segment replacement. A shared read lock is
+ * aquired for an index replacement. An exclusive write lock is acquired
+ * when this index merger is shuting down, to prevent further index
+ * replacements.
*/
- private final Semaphore indexReplacement;
+ private final ReadWriteLock indexReplacement = new ReentrantReadWriteLock();
/**
* List of merger threads that are currently busy.
@@ -91,32 +104,23 @@
private final List<Worker> busyMergers = new ArrayList<Worker>();
/**
- * List of merger threads.
- */
- private final List<Worker> workers = new ArrayList<Worker>();
-
- /**
* Creates an <code>IndexMerger</code>.
*
* @param multiIndex the <code>MultiIndex</code>.
- * @param numWorkers the number of worker threads to use.
+ * @param executor the executor of the repository.
*/
- IndexMerger(MultiIndex multiIndex, int numWorkers) {
+ IndexMerger(MultiIndex multiIndex, Executor executor) {
this.multiIndex = multiIndex;
- for (int i = 0; i < numWorkers; i++) {
- Worker w = new Worker();
- workers.add(w);
- busyMergers.add(w);
- }
- this.indexReplacement = new Semaphore(workers.size());
+ this.executor = executor;
}
/**
* Starts this index merger.
*/
void start() {
- for (Thread t : workers) {
- t.start();
+ isStarted.set(true);
+ for (Worker worker : busyMergers) {
+ worker.unblock();
}
}
@@ -190,7 +194,6 @@
}
addMergeTask(new Merge(idxs));
if (log.isDebugEnabled()) {
- log.debug("merge queue now contains " + mergeTasks.size() + " tasks.");
int numBusy;
synchronized (busyMergers) {
numBusy = busyMergers.size();
@@ -236,21 +239,17 @@
*/
void dispose() {
log.debug("dispose IndexMerger");
- // get all permits for index replacements
+ // get exclusive lock on index replacements
try {
- indexReplacement.acquire(workers.size());
+ indexReplacement.writeLock().lockInterruptibly();
} catch (InterruptedException e) {
- log.warn("Interrupted while acquiring index replacement permits: " + e);
+ log.warn("Interrupted while acquiring index replacement exclusive lock: " + e);
// try to stop IndexMerger without the sync
}
- log.debug("merge queue size: " + mergeTasks.size());
- // clear task queue
- mergeTasks.clear();
-
- // send quit
- addMergeTask(QUIT);
- log.debug("quit sent");
+ // set quit
+ quit.set(true);
+ log.debug("quit flag set");
try {
// give the merger threads some time to quit,
@@ -259,9 +258,13 @@
// die without being able to finish the merge.
// at this point it is not possible anymore to replace indexes
// on the MultiIndex because we hold all indexReplacement permits.
- for (Thread t : workers) {
- t.join(500);
- if (t.isAlive()) {
+ Worker[] workers;
+ synchronized (busyMergers) {
+ workers = busyMergers.toArray(new Worker[busyMergers.size()]);
+ }
+ for (Worker w : workers) {
+ w.join(500);
+ if (w.isAlive()) {
log.info("Unable to stop IndexMerger.Worker. Daemon is busy.");
} else {
log.debug("IndexMerger.Worker thread stopped");
@@ -305,14 +308,17 @@
//------------------------------< internal >--------------------------------
private void addMergeTask(Merge task) {
- for (;;) {
- try {
- mergeTasks.put(task);
- break;
- } catch (InterruptedException e) {
- // try again
- Thread.interrupted();
+ // only enqueue if still running
+ if (!quit.get()) {
+ Worker worker = new Worker(task);
+ if (isStarted.get()) {
+ // immediately unblock if this index merger is already started
+ worker.unblock();
+ }
+ synchronized (busyMergers) {
+ busyMergers.add(worker);
}
+ executor.execute(worker);
}
}
@@ -448,7 +454,7 @@
}
}
- private class Worker extends Thread implements IndexListener {
+ private class Worker implements Runnable, IndexListener {
/**
* List of id <code>Term</code> that identify documents that were deleted
@@ -456,53 +462,50 @@
*/
private final List<Term> deletedDocuments = Collections.synchronizedList(new ArrayList<Term>());
- public Worker() {
- setName("IndexMerger.Worker");
- setDaemon(true);
+ /**
+ * A latch that is set to zero when this worker is unblocked.
+ */
+ private final CountDownLatch start = new CountDownLatch(1);
+
+ /**
+ * Flat that indicates whether this woker has finished its work.
+ */
+ private final AtomicBoolean terminated = new AtomicBoolean(true);
+
+ /**
+ * The merge task.
+ */
+ private final Merge task;
+
+ /**
+ * Creates a new worker which is initially blocked. Call
+ * {@link #unblock()} to unblock it.
+ *
+ * @param task the merge task.
+ */
+ private Worker(Merge task) {
+ this.task = task;
}
/**
* Implements the index merging.
*/
public void run() {
- for (;;) {
- boolean isIdle = false;
- if (mergeTasks.size() == 0) {
- synchronized (busyMergers) {
- busyMergers.remove(this);
- busyMergers.notifyAll();
- }
- isIdle = true;
- }
- Merge task;
- for (;;) {
- try {
- task = mergeTasks.take();
- break;
- } catch (InterruptedException e) {
- // try again
- Thread.interrupted();
- }
- }
- if (task == QUIT) {
- synchronized (busyMergers) {
- busyMergers.remove(this);
- }
- // put back QUIT to signal other workers
- addMergeTask(task);
- break;
- }
- if (isIdle) {
- synchronized (busyMergers) {
- busyMergers.add(this);
+ // worker is initially suspended
+ try {
+ try {
+ start.await();
+ } catch (InterruptedException e) {
+ // check if we should quit
+ if (!quit.get()) {
+ // enqueue task again and retry with another thread
+ addMergeTask(task);
}
+ return;
}
log.debug("accepted merge request");
- // reset deleted documents
- deletedDocuments.clear();
-
// get readers
String[] names = new String[task.indexes.length];
for (int i = 0; i < task.indexes.length; i++) {
@@ -538,15 +541,16 @@
// inform multi index
// if we cannot get the sync immediately we have to quit
- if (!indexReplacement.tryAcquire()) {
+ Lock shared = indexReplacement.readLock();
+ if (!shared.tryLock()) {
log.debug("index merging canceled");
- break;
+ return;
}
try {
log.debug("replace indexes");
multiIndex.replaceIndexes(names, index, deletedDocuments);
} finally {
- indexReplacement.release();
+ shared.unlock();
}
success = true;
@@ -556,13 +560,24 @@
// delete index
log.debug("deleting index " + index.getName());
multiIndex.deleteIndex(index);
+ // add task again and retry
+ addMergeTask(task);
}
}
} catch (Throwable e) {
log.error("Error while merging indexes: ", e);
}
+ } finally {
+ synchronized (terminated) {
+ terminated.set(true);
+ terminated.notifyAll();
+ }
+ synchronized (busyMergers) {
+ busyMergers.remove(this);
+ busyMergers.notifyAll();
+ }
+ log.debug("Worker finished");
}
- log.info("IndexMerger.Worker terminated");
}
/**
@@ -572,5 +587,37 @@
log.debug("document deleted: " + id.text());
deletedDocuments.add(id);
}
+
+ /**
+ * Unblocks this worker and allows it to start with the index merging.
+ */
+ void unblock() {
+ start.countDown();
+ }
+
+ /**
+ * Waits until this worker is finished or the specified amount of time
+ * has elapsed.
+ *
+ * @param timeout the timeout in milliseconds.
+ * @throws InterruptedException if the current thread is interrupted
+ * while waiting for this worker to
+ * terminate.
+ */
+ void join(long timeout) throws InterruptedException {
+ synchronized (terminated) {
+ while (!terminated.get()) {
+ terminated.wait(timeout);
+ }
+ }
+ }
+
+ /**
+ * @return <code>true</code> if this worker is still alive and not yet
+ * terminated.
+ */
+ boolean isAlive() {
+ return !terminated.get();
+ }
}
}
Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java Wed Nov 25 14:04:38 2009
@@ -16,23 +16,32 @@
*/
package org.apache.jackrabbit.core.query.lucene;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TermEnum;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.document.Fieldable;
+import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.FilterIndexReader;
import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.CorruptIndexException;
-import org.apache.lucene.index.TermPositions;
import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.index.TermPositions;
import org.apache.lucene.store.Directory;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.FieldSelector;
-import org.apache.lucene.document.Fieldable;
-import org.apache.lucene.document.Field;
-import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager;
-import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
-
-import java.io.IOException;
+import org.slf4j.LoggerFactory;
/**
* <code>IndexMigration</code> implements a utility that migrates a Jackrabbit
@@ -55,10 +64,12 @@
*
* @param index the index to check and migration if needed.
* @param directoryManager the directory manager.
+ * @param oldSeparatorChar the old separator char that needs to be replaced.
* @throws IOException if an error occurs while migrating the index.
*/
public static void migrate(PersistentIndex index,
- DirectoryManager directoryManager)
+ DirectoryManager directoryManager,
+ char oldSeparatorChar)
throws IOException {
Directory indexDir = index.getDirectory();
log.debug("Checking {} ...", indexDir);
@@ -76,7 +87,7 @@
TermEnum terms = reader.terms(new Term(FieldNames.PROPERTIES, ""));
try {
Term t = terms.term();
- if (t.text().indexOf('\uFFFF') == -1) {
+ if (t.text().indexOf(oldSeparatorChar) == -1) {
log.debug("Index already migrated");
return;
}
@@ -102,7 +113,8 @@
IndexWriter.MaxFieldLength.UNLIMITED);
try {
IndexReader r = new MigrationIndexReader(
- IndexReader.open(index.getDirectory()));
+ IndexReader.open(index.getDirectory()),
+ oldSeparatorChar);
try {
writer.addIndexes(new IndexReader[]{r});
writer.close();
@@ -131,8 +143,11 @@
*/
private static class MigrationIndexReader extends FilterIndexReader {
- public MigrationIndexReader(IndexReader in) {
+ private final char oldSepChar;
+
+ public MigrationIndexReader(IndexReader in, char oldSepChar) {
super(in);
+ this.oldSepChar = oldSepChar;
}
public Document document(int n, FieldSelector fieldSelector)
@@ -143,7 +158,7 @@
doc.removeFields(FieldNames.PROPERTIES);
for (Fieldable field : fields) {
String value = field.stringValue();
- value = value.replace('\uFFFF', '[');
+ value = value.replace(oldSepChar, '[');
doc.add(new Field(FieldNames.PROPERTIES, value, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
}
}
@@ -151,17 +166,60 @@
}
public TermEnum terms() throws IOException {
- return new MigrationTermEnum(in.terms());
+ List<TermEnum> enums = new ArrayList<TermEnum>();
+ List<String> fieldNames = new ArrayList<String>();
+ for (Object obj : in.getFieldNames(FieldOption.ALL)) {
+ fieldNames.add((String) obj);
+ }
+ Collections.sort(fieldNames);
+ for (String fieldName : fieldNames) {
+ if (fieldName.equals(FieldNames.PROPERTIES)) {
+ addPropertyTerms(enums);
+ } else {
+ enums.add(new RangeScan(in, new Term(fieldName, ""), new Term(fieldName, "\uFFFF")));
+ }
+ }
+ return new MigrationTermEnum(new ChainedTermEnum(enums), oldSepChar);
}
public TermPositions termPositions() throws IOException {
- return new MigrationTermPositions(in.termPositions());
+ return new MigrationTermPositions(in.termPositions(), oldSepChar);
+ }
+
+ private void addPropertyTerms(List<TermEnum> enums) throws IOException {
+ SortedMap<String, TermEnum> termEnums = new TreeMap<String, TermEnum>(
+ new Comparator<String>() {
+ public int compare(String s1, String s2) {
+ s1 = s1.replace(oldSepChar, '[');
+ s2 = s2.replace(oldSepChar, '[');
+ return s1.compareTo(s2);
+ }
+ });
+ // scan through terms and find embedded field names
+ TermEnum terms = new RangeScan(in,
+ new Term(FieldNames.PROPERTIES, ""),
+ new Term(FieldNames.PROPERTIES, "\uFFFF"));
+ String previous = null;
+ while (terms.next()) {
+ Term t = terms.term();
+ String name = t.text().substring(0, t.text().indexOf(oldSepChar) + 1);
+ if (!name.equals(previous)) {
+ termEnums.put(name, new RangeScan(in,
+ new Term(FieldNames.PROPERTIES, name),
+ new Term(FieldNames.PROPERTIES, name + "\uFFFF")));
+ }
+ previous = name;
+ }
+ enums.addAll(termEnums.values());
}
private static class MigrationTermEnum extends FilterTermEnum {
- public MigrationTermEnum(TermEnum in) {
+ private final char oldSepChar;
+
+ public MigrationTermEnum(TermEnum in, char oldSepChar) {
super(in);
+ this.oldSepChar = oldSepChar;
}
public Term term() {
@@ -171,7 +229,7 @@
}
if (t.field().equals(FieldNames.PROPERTIES)) {
String text = t.text();
- return t.createTerm(text.replace('\uFFFF', '['));
+ return t.createTerm(text.replace(oldSepChar, '['));
} else {
return t;
}
@@ -184,14 +242,17 @@
private static class MigrationTermPositions extends FilterTermPositions {
- public MigrationTermPositions(TermPositions in) {
+ private final char oldSepChar;
+
+ public MigrationTermPositions(TermPositions in, char oldSepChar) {
super(in);
+ this.oldSepChar = oldSepChar;
}
public void seek(Term term) throws IOException {
if (term.field().equals(FieldNames.PROPERTIES)) {
char[] text = term.text().toCharArray();
- text[term.text().indexOf('[')] = '\uFFFF';
+ text[term.text().indexOf('[')] = oldSepChar;
super.seek(term.createTerm(new String(text)));
} else {
super.seek(term);
@@ -207,4 +268,54 @@
}
}
}
+
+ private static final class ChainedTermEnum extends TermEnum {
+
+ private Queue<TermEnum> queue = new LinkedList<TermEnum>();
+
+ public ChainedTermEnum(Collection<TermEnum> enums) {
+ super();
+ queue.addAll(enums);
+ }
+
+ public boolean next() throws IOException {
+ for (;;) {
+ TermEnum terms = queue.peek();
+ if (terms == null) {
+ // no more enums
+ break;
+ }
+ if (terms.next()) {
+ return true;
+ } else {
+ queue.remove();
+ terms.close();
+ }
+ }
+ return false;
+ }
+
+ public Term term() {
+ TermEnum terms = queue.peek();
+ if (terms != null) {
+ return terms.term();
+ }
+ return null;
+ }
+
+ public int docFreq() {
+ TermEnum terms = queue.peek();
+ if (terms != null) {
+ return terms.docFreq();
+ }
+ return 0;
+ }
+
+ public void close() throws IOException {
+ // close remaining
+ while (!queue.isEmpty()) {
+ queue.remove().close();
+ }
+ }
+ }
}