<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry kind="src" output="target/classes" path="src/main/resources"/>
- <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
- <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
com.springsource.org.apache.commons.collections,\
com.springsource.edu.oswego.cs.dl.util.concurrent,\
com.springsource.org.apache.derby,\
- com.springsource.org.apache.lucene
+ com.springsource.org.apache.lucene,\
+ org.springframework.context
source.. = src/main/java/,\
src/test/java/,\
src/test/resources/,\
+++ /dev/null
-<?xml version="1.0"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
- "http://jackrabbit.apache.org/dtd/repository-1.6.dtd">
-<!-- Example Repository Configuration File
- Used by
- - org.apache.jackrabbit.core.config.RepositoryConfigTest.java
- -
--->
-<Repository>
- <!--
- virtual file system where the repository stores global state
- (e.g. registered namespaces, custom node types, etc.)
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
- <param name="path" value="${rep.home}/repository"/>
- </FileSystem>
-
- <!--
- security configuration
- -->
- <Security appName="Jackrabbit">
- <!--
- security manager:
- class: FQN of class implementing the JackrabbitSecurityManager interface
- -->
- <SecurityManager class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager" workspaceName="security">
- <!--
- workspace access:
- class: FQN of class implementing the WorkspaceAccessManager interface
- -->
- <!-- <WorkspaceAccessManager class="..."/> -->
- <!-- <param name="config" value="${rep.home}/security.xml"/> -->
- </SecurityManager>
-
- <!--
- access manager:
- class: FQN of class implementing the AccessManager interface
- -->
- <AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
- <!-- <param name="config" value="${rep.home}/access.xml"/> -->
- </AccessManager>
-
- <LoginModule class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
- <!--
- anonymous user name ('anonymous' is the default value)
- -->
- <param name="anonymousId" value="anonymous"/>
- <!--
- administrator user id (default value if param is missing is 'admin')
- -->
- <param name="adminId" value="admin"/>
- </LoginModule>
- </Security>
-
- <!--
- location of workspaces root directory and name of default workspace
- -->
- <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
- <!--
- workspace configuration template:
- used to create the initial workspace if there's no workspace yet
- -->
- <Workspace name="${wsp.name}">
- <!--
- virtual file system of the workspace:
- class: FQN of class implementing the FileSystem interface
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
- <param name="path" value="${wsp.home}"/>
- </FileSystem>
- <!--
- persistence manager of the workspace:
- class: FQN of class implementing the PersistenceManager interface
- -->
- <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
- <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
- <param name="schemaObjectPrefix" value="${wsp.name}_"/>
- </PersistenceManager>
- <!--
- Search index and the file system it uses.
- class: FQN of class implementing the QueryHandler interface
- -->
- <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
- <param name="path" value="${wsp.home}/index"/>
- <param name="extractorPoolSize" value="2"/>
- <param name="supportHighlighting" value="true"/>
- </SearchIndex>
- </Workspace>
-
- <!--
- Configures the versioning
- -->
- <Versioning rootPath="${rep.home}/version">
- <!--
- Configures the filesystem to use for versioning for the respective
- persistence manager
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
- <param name="path" value="${rep.home}/version" />
- </FileSystem>
-
- <!--
- Configures the persistence manager to be used for persisting version state.
- Please note that the current versioning implementation is based on
- a 'normal' persistence manager, but this could change in future
- implementations.
- -->
- <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
- <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
- <param name="schemaObjectPrefix" value="version_"/>
- </PersistenceManager>
- </Versioning>
-
- <!--
- Search index for content that is shared repository wide
- (/jcr:system tree, contains mainly versions)
- -->
- <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
- <param name="path" value="${rep.home}/repository/index"/>
- <param name="extractorPoolSize" value="2"/>
- <param name="supportHighlighting" value="true"/>
- </SearchIndex>
-</Repository>
+++ /dev/null
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.jcr;
-
-/**
- * Copied from org.apache.jackrabbit.JcrConstants v1.6.0 in order to avoid a
- * dependency to Jackrabbit.
- */
-public interface ArgeoJcrConstants {
- /**
- * jcr:autoCreated
- */
- public static final String JCR_AUTOCREATED = "jcr:autoCreated";
- /**
- * jcr:baseVersion
- */
- public static final String JCR_BASEVERSION = "jcr:baseVersion";
- /**
- * jcr:child
- */
- public static final String JCR_CHILD = "jcr:child";
- /**
- * jcr:childNodeDefinition
- */
- public static final String JCR_CHILDNODEDEFINITION = "jcr:childNodeDefinition";
- /**
- * jcr:content
- */
- public static final String JCR_CONTENT = "jcr:content";
- /**
- * jcr:created
- */
- public static final String JCR_CREATED = "jcr:created";
- /**
- * jcr:data
- */
- public static final String JCR_DATA = "jcr:data";
- /**
- * jcr:defaultPrimaryType
- */
- public static final String JCR_DEFAULTPRIMARYTYPE = "jcr:defaultPrimaryType";
- /**
- * jcr:defaultValues
- */
- public static final String JCR_DEFAULTVALUES = "jcr:defaultValues";
- /**
- * jcr:encoding
- */
- public static final String JCR_ENCODING = "jcr:encoding";
- /**
- * jcr:frozenMixinTypes
- */
- public static final String JCR_FROZENMIXINTYPES = "jcr:frozenMixinTypes";
- /**
- * jcr:frozenNode
- */
- public static final String JCR_FROZENNODE = "jcr:frozenNode";
- /**
- * jcr:frozenPrimaryType
- */
- public static final String JCR_FROZENPRIMARYTYPE = "jcr:frozenPrimaryType";
- /**
- * jcr:frozenUuid
- */
- public static final String JCR_FROZENUUID = "jcr:frozenUuid";
- /**
- * jcr:hasOrderableChildNodes
- */
- public static final String JCR_HASORDERABLECHILDNODES = "jcr:hasOrderableChildNodes";
- /**
- * jcr:isCheckedOut
- */
- public static final String JCR_ISCHECKEDOUT = "jcr:isCheckedOut";
- /**
- * jcr:isMixin
- */
- public static final String JCR_ISMIXIN = "jcr:isMixin";
- /**
- * jcr:language
- */
- public static final String JCR_LANGUAGE = "jcr:language";
- /**
- * jcr:lastModified
- */
- public static final String JCR_LASTMODIFIED = "jcr:lastModified";
- /**
- * jcr:lockIsDeep
- */
- public static final String JCR_LOCKISDEEP = "jcr:lockIsDeep";
- /**
- * jcr:lockOwner
- */
- public static final String JCR_LOCKOWNER = "jcr:lockOwner";
- /**
- * jcr:mandatory
- */
- public static final String JCR_MANDATORY = "jcr:mandatory";
- /**
- * jcr:mergeFailed
- */
- public static final String JCR_MERGEFAILED = "jcr:mergeFailed";
- /**
- * jcr:mimeType
- */
- public static final String JCR_MIMETYPE = "jcr:mimeType";
- /**
- * jcr:mixinTypes
- */
- public static final String JCR_MIXINTYPES = "jcr:mixinTypes";
- /**
- * jcr:multiple
- */
- public static final String JCR_MULTIPLE = "jcr:multiple";
- /**
- * jcr:name
- */
- public static final String JCR_NAME = "jcr:name";
- /**
- * jcr:nodeTypeName
- */
- public static final String JCR_NODETYPENAME = "jcr:nodeTypeName";
- /**
- * jcr:onParentVersion
- */
- public static final String JCR_ONPARENTVERSION = "jcr:onParentVersion";
- /**
- * jcr:predecessors
- */
- public static final String JCR_PREDECESSORS = "jcr:predecessors";
- /**
- * jcr:primaryItemName
- */
- public static final String JCR_PRIMARYITEMNAME = "jcr:primaryItemName";
- /**
- * jcr:primaryType
- */
- public static final String JCR_PRIMARYTYPE = "jcr:primaryType";
- /**
- * jcr:propertyDefinition
- */
- public static final String JCR_PROPERTYDEFINITION = "jcr:propertyDefinition";
- /**
- * jcr:protected
- */
- public static final String JCR_PROTECTED = "jcr:protected";
- /**
- * jcr:requiredPrimaryTypes
- */
- public static final String JCR_REQUIREDPRIMARYTYPES = "jcr:requiredPrimaryTypes";
- /**
- * jcr:requiredType
- */
- public static final String JCR_REQUIREDTYPE = "jcr:requiredType";
- /**
- * jcr:rootVersion
- */
- public static final String JCR_ROOTVERSION = "jcr:rootVersion";
- /**
- * jcr:sameNameSiblings
- */
- public static final String JCR_SAMENAMESIBLINGS = "jcr:sameNameSiblings";
- /**
- * jcr:statement
- */
- public static final String JCR_STATEMENT = "jcr:statement";
- /**
- * jcr:successors
- */
- public static final String JCR_SUCCESSORS = "jcr:successors";
- /**
- * jcr:supertypes
- */
- public static final String JCR_SUPERTYPES = "jcr:supertypes";
- /**
- * jcr:system
- */
- public static final String JCR_SYSTEM = "jcr:system";
- /**
- * jcr:uuid
- */
- public static final String JCR_UUID = "jcr:uuid";
- /**
- * jcr:valueConstraints
- */
- public static final String JCR_VALUECONSTRAINTS = "jcr:valueConstraints";
- /**
- * jcr:versionHistory
- */
- public static final String JCR_VERSIONHISTORY = "jcr:versionHistory";
- /**
- * jcr:versionLabels
- */
- public static final String JCR_VERSIONLABELS = "jcr:versionLabels";
- /**
- * jcr:versionStorage
- */
- public static final String JCR_VERSIONSTORAGE = "jcr:versionStorage";
- /**
- * jcr:versionableUuid
- */
- public static final String JCR_VERSIONABLEUUID = "jcr:versionableUuid";
-
- /**
- * Pseudo property jcr:path used with query results
- */
- public static final String JCR_PATH = "jcr:path";
- /**
- * Pseudo property jcr:score used with query results
- */
- public static final String JCR_SCORE = "jcr:score";
-
- /**
- * mix:lockable
- */
- public static final String MIX_LOCKABLE = "mix:lockable";
- /**
- * mix:referenceable
- */
- public static final String MIX_REFERENCEABLE = "mix:referenceable";
- /**
- * mix:versionable
- */
- public static final String MIX_VERSIONABLE = "mix:versionable";
- /**
- * mix:shareable
- */
- public static final String MIX_SHAREABLE = "mix:shareable";
- /**
- * nt:base
- */
- public static final String NT_BASE = "nt:base";
- /**
- * nt:childNodeDefinition
- */
- public static final String NT_CHILDNODEDEFINITION = "nt:childNodeDefinition";
- /**
- * nt:file
- */
- public static final String NT_FILE = "nt:file";
- /**
- * nt:folder
- */
- public static final String NT_FOLDER = "nt:folder";
- /**
- * nt:frozenNode
- */
- public static final String NT_FROZENNODE = "nt:frozenNode";
- /**
- * nt:hierarchyNode
- */
- public static final String NT_HIERARCHYNODE = "nt:hierarchyNode";
- /**
- * nt:linkedFile
- */
- public static final String NT_LINKEDFILE = "nt:linkedFile";
- /**
- * nt:nodeType
- */
- public static final String NT_NODETYPE = "nt:nodeType";
- /**
- * nt:propertyDefinition
- */
- public static final String NT_PROPERTYDEFINITION = "nt:propertyDefinition";
- /**
- * nt:query
- */
- public static final String NT_QUERY = "nt:query";
- /**
- * nt:resource
- */
- public static final String NT_RESOURCE = "nt:resource";
- /**
- * nt:unstructured
- */
- public static final String NT_UNSTRUCTURED = "nt:unstructured";
- /**
- * nt:version
- */
- public static final String NT_VERSION = "nt:version";
- /**
- * nt:versionHistory
- */
- public static final String NT_VERSIONHISTORY = "nt:versionHistory";
- /**
- * nt:versionLabels
- */
- public static final String NT_VERSIONLABELS = "nt:versionLabels";
- /**
- * nt:versionedChild
- */
- public static final String NT_VERSIONEDCHILD = "nt:versionedChild";
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import java.beans.PropertyDescriptor;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.ValueFactory;
-
-import org.argeo.ArgeoException;
-import org.springframework.beans.BeanWrapper;
-import org.springframework.beans.BeanWrapperImpl;
-
-public class BeanNodeMapper implements NodeMapper {
- // private final static Log log = LogFactory.getLog(BeanNodeMapper.class);
-
- private final static String NODE_VALUE = "value";
-
- // private String keyNode = "bean:key";
- private String uuidProperty = "uuid";
- private String classProperty = "class";
-
- private Boolean versioning = false;
- private Boolean strictUuidReference = false;
-
- // TODO define a primaryNodeType Strategy
- private String primaryNodeType = null;
-
- private ClassLoader classLoader = getClass().getClassLoader();
-
- private NodeMapperProvider nodeMapperProvider;
-
- /**
- * exposed method to retrieve a bean from a node
- */
- public Object load(Node node) {
- try {
- if (nodeMapperProvider != null) {
- NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node);
- if (nodeMapper != this) {
- return nodeMapper.load(node);
- }
- }
- return nodeToBean(node);
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot load object from node " + node, e);
- }
- }
-
- /** Update an existing node with an object */
- public void update(Node node, Object obj) {
- try {
- if (nodeMapperProvider != null) {
-
- NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node);
- if (nodeMapper != this) {
- nodeMapper.update(node, obj);
- } else
- beanToNode(createBeanWrapper(obj), node);
- } else
- beanToNode(createBeanWrapper(obj), node);
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot update node " + node + " with "
- + obj, e);
- }
- }
-
- /**
- * if no storage path is given; we use canonical path
- *
- * @see this.storagePath()
- */
- public Node save(Session session, Object obj) {
- return save(session, storagePath(obj), obj);
- }
-
- /**
- * Create a new node to store an object. If the parentNode doesn't exist, it
- * is created
- *
- * the primaryNodeType may be initialized before
- */
- public Node save(Session session, String path, Object obj) {
- try {
- final Node node;
- String parentPath = JcrUtils.parentPath(path);
- // find or create parent node
- Node parentNode;
- if (session.itemExists(path))
- parentNode = (Node) session.getItem(parentPath);
- else {
- parentNode = JcrUtils.mkdirs(session, parentPath, null,
- versioning);
- }
- // create node
-
- if (primaryNodeType != null)
- node = parentNode.addNode(JcrUtils.lastPathElement(path),
- primaryNodeType);
- else
- node = parentNode.addNode(JcrUtils.lastPathElement(path));
-
- // Check specific cases
- if (nodeMapperProvider != null) {
- NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node);
- if (nodeMapper != this) {
- nodeMapper.update(node, obj);
- return node;
- }
- }
- update(node, obj);
- return node;
- } catch (ArgeoException e) {
- throw e;
- } catch (Exception e) {
- throw new ArgeoException("Cannot save or update " + obj + " under "
- + path, e);
- }
- }
-
- /**
- * Parse the FQN of a class to string with '/' delimiters Prefix the
- * returned string with "/objects/"
- */
- public String storagePath(Object obj) {
- String clss = obj.getClass().getName();
- StringBuffer buf = new StringBuffer("/objects/");
- StringTokenizer st = new StringTokenizer(clss, ".");
- while (st.hasMoreTokens()) {
- buf.append(st.nextToken()).append('/');
- }
- buf.append(obj.toString());
- return buf.toString();
- }
-
- @SuppressWarnings("unchecked")
- /**
- * Transforms a node into an object of the class defined by classProperty Property
- */
- protected Object nodeToBean(Node node) throws RepositoryException {
-
- try {
- String clssName = node.getProperty(classProperty).getValue()
- .getString();
-
- BeanWrapper beanWrapper = createBeanWrapper(loadClass(clssName));
-
- // process properties
- PropertyIterator propIt = node.getProperties();
- props: while (propIt.hasNext()) {
- Property prop = propIt.nextProperty();
- if (!beanWrapper.isWritableProperty(prop.getName()))
- continue props;
-
- PropertyDescriptor pd = beanWrapper.getPropertyDescriptor(prop
- .getName());
- Class propClass = pd.getPropertyType();
-
- // Process case of List and its derived classes
- // primitive list
- if (propClass != null && List.class.isAssignableFrom(propClass)) {
- List<Object> lst = new ArrayList<Object>();
- Class<?> valuesClass = classFromProperty(prop);
- if (valuesClass != null)
- for (Value value : prop.getValues()) {
- lst.add(asObject(value, valuesClass));
- }
- continue props;
- }
-
- // Case of other type of property accepted by jcr
- // Long, Double, String, Binary, Date, Boolean, Name
- Object value = asObject(prop.getValue(), pd.getPropertyType());
- if (value != null)
- beanWrapper.setPropertyValue(prop.getName(), value);
- }
-
- // process children nodes
- NodeIterator nodeIt = node.getNodes();
- nodes: while (nodeIt.hasNext()) {
- Node childNode = nodeIt.nextNode();
- String name = childNode.getName();
- if (!beanWrapper.isWritableProperty(name))
- continue nodes;
-
- PropertyDescriptor pd = beanWrapper.getPropertyDescriptor(name);
- Class propClass = pd.getPropertyType();
-
- // objects list
- if (propClass != null && List.class.isAssignableFrom(propClass)) {
- String lstClass = childNode.getProperty(classProperty)
- .getString();
- List<Object> lst;
- try {
- lst = (List<Object>) loadClass(lstClass).newInstance();
- } catch (Exception e) {
- lst = new ArrayList<Object>();
- }
-
- NodeIterator valuesIt = childNode.getNodes();
- while (valuesIt.hasNext()) {
- Node lstValueNode = valuesIt.nextNode();
- Object lstValue = nodeToBean(lstValueNode);
- lst.add(lstValue);
- }
-
- beanWrapper.setPropertyValue(name, lst);
- continue nodes;
- }
-
- // objects map
- if (propClass != null && Map.class.isAssignableFrom(propClass)) {
- String mapClass = childNode.getProperty(classProperty)
- .getString();
- Map<Object, Object> map;
- try {
- map = (Map<Object, Object>) loadClass(mapClass)
- .newInstance();
- } catch (Exception e) {
- map = new HashMap<Object, Object>();
- }
-
- // properties
- PropertyIterator keysPropIt = childNode.getProperties();
- keyProps: while (keysPropIt.hasNext()) {
- Property keyProp = keysPropIt.nextProperty();
- // FIXME: use property editor
- String key = keyProp.getName();
- if (classProperty.equals(key))
- continue keyProps;
-
- Class keyPropClass = classFromProperty(keyProp);
- if (keyPropClass != null) {
- Object mapValue = asObject(keyProp.getValue(),
- keyPropClass);
- map.put(key, mapValue);
- }
- }
-
- // node
- NodeIterator keysIt = childNode.getNodes();
- while (keysIt.hasNext()) {
- Node mapValueNode = keysIt.nextNode();
- // FIXME: use property editor
- Object key = mapValueNode.getName();
-
- Object mapValue = nodeToBean(mapValueNode);
-
- map.put(key, mapValue);
- }
- beanWrapper.setPropertyValue(name, map);
- continue nodes;
- }
-
- // default
- Object value = nodeToBean(childNode);
- beanWrapper.setPropertyValue(name, value);
-
- }
- return beanWrapper.getWrappedInstance();
- } catch (Exception e) {
- throw new ArgeoException("Cannot map node " + node, e);
- }
- }
-
- /**
- * Transforms an object to the specified jcr Node in order to persist it.
- *
- * @param beanWrapper
- * @param node
- * @throws RepositoryException
- */
- protected void beanToNode(BeanWrapper beanWrapper, Node node)
- throws RepositoryException {
- properties: for (PropertyDescriptor pd : beanWrapper
- .getPropertyDescriptors()) {
- String name = pd.getName();
- if (!beanWrapper.isReadableProperty(name))
- continue properties;// skip
-
- Object value = beanWrapper.getPropertyValue(name);
- if (value == null) {
- // remove values when updating
- if (node.hasProperty(name))
- node.setProperty(name, (Value) null);
- if (node.hasNode(name))
- node.getNode(name).remove();
-
- continue properties;
- }
-
- // if (uuidProperty != null && uuidProperty.equals(name)) {
- // // node.addMixin(ArgeoJcrConstants.MIX_REFERENCEABLE);
- // node.setProperty(ArgeoJcrConstants.JCR_UUID, value.toString());
- // continue properties;
- // }
-
- if ("class".equals(name)) {
- if (classProperty != null) {
- node.setProperty(classProperty, ((Class<?>) value)
- .getName());
- // TODO: store a class hierarchy?
- }
- continue properties;
- }
-
- // Some bean reference other classes. We must deal with this case
- if (value instanceof Class<?>) {
- node.setProperty(name, ((Class<?>) value).getName());
- continue properties;
- }
-
- Value val = asValue(node.getSession(), value);
- if (val != null) {
- node.setProperty(name, val);
- continue properties;
- }
-
- if (value instanceof List<?>) {
- List<?> lst = (List<?>) value;
- addList(node, name, lst);
- continue properties;
- }
-
- if (value instanceof Map<?, ?>) {
- Map<?, ?> map = (Map<?, ?>) value;
- addMap(node, name, map);
- continue properties;
- }
-
- BeanWrapper child = createBeanWrapper(value);
- // TODO: delegate to another mapper
-
- // TODO: deal with references
- // Node childNode = findChildReference(session, child);
- // if (childNode != null) {
- // node.setProperty(name, childNode);
- // continue properties;
- // }
-
- // default case (recursive)
- if (node.hasNode(name)) {// update
- // TODO: optimize
- node.getNode(name).remove();
- }
- Node childNode = node.addNode(name);
- beanToNode(child, childNode);
- }
- }
-
- /**
- * Process specific case of list
- *
- * @param node
- * @param name
- * @param lst
- * @throws RepositoryException
- */
- protected void addList(Node node, String name, List<?> lst)
- throws RepositoryException {
- if (node.hasNode(name)) {// update
- // TODO: optimize
- node.getNode(name).remove();
- }
-
- Node listNode = node.addNode(name);
- listNode.setProperty(classProperty, lst.getClass().getName());
- Value[] values = new Value[lst.size()];
- boolean atLeastOneSet = false;
- for (int i = 0; i < lst.size(); i++) {
- Object lstValue = lst.get(i);
- values[i] = asValue(node.getSession(), lstValue);
- if (values[i] != null) {
- atLeastOneSet = true;
- } else {
- Node childNode = findChildReference(node.getSession(),
- createBeanWrapper(lstValue));
- if (childNode != null) {
- values[i] = node.getSession().getValueFactory()
- .createValue(childNode);
- atLeastOneSet = true;
- }
- }
- }
-
- // will be either properties or nodes, not both
- if (!atLeastOneSet && lst.size() != 0) {
- for (Object lstValue : lst) {
- Node childNode = listNode.addNode(NODE_VALUE);
- beanToNode(createBeanWrapper(lstValue), childNode);
- }
- } else {
- listNode.setProperty(name, values);
- }
- }
-
- /**
- * Process specific case of maps.
- *
- * @param node
- * @param name
- * @param map
- * @throws RepositoryException
- */
- protected void addMap(Node node, String name, Map<?, ?> map)
- throws RepositoryException {
- if (node.hasNode(name)) {// update
- // TODO: optimize
- node.getNode(name).remove();
- }
-
- Node mapNode = node.addNode(name);
- mapNode.setProperty(classProperty, map.getClass().getName());
- for (Object key : map.keySet()) {
- Object mapValue = map.get(key);
- // PropertyEditor pe = beanWrapper.findCustomEditor(key.getClass(),
- // null);
- String keyStr;
- // if (pe == null) {
- if (key instanceof CharSequence)
- keyStr = key.toString();
- else
- throw new ArgeoException(
- "Cannot find property editor for class "
- + key.getClass());
- // } else {
- // pe.setValue(key);
- // keyStr = pe.getAsText();
- // }
- // TODO: check string format
-
- Value mapVal = asValue(node.getSession(), mapValue);
- if (mapVal != null)
- mapNode.setProperty(keyStr, mapVal);
- else {
- Node entryNode = mapNode.addNode(keyStr);
- beanToNode(createBeanWrapper(mapValue), entryNode);
- }
-
- }
-
- }
-
- protected BeanWrapper createBeanWrapper(Object obj) {
- return new BeanWrapperImpl(obj);
- }
-
- protected BeanWrapper createBeanWrapper(Class<?> clss) {
- return new BeanWrapperImpl(clss);
- }
-
- /** Returns null if value cannot be found */
- protected Value asValue(Session session, Object value)
- throws RepositoryException {
- ValueFactory valueFactory = session.getValueFactory();
- if (value instanceof Integer)
- return valueFactory.createValue((Integer) value);
- else if (value instanceof Long)
- return valueFactory.createValue((Long) value);
- else if (value instanceof Float)
- return valueFactory.createValue((Float) value);
- else if (value instanceof Double)
- return valueFactory.createValue((Double) value);
- else if (value instanceof Boolean)
- return valueFactory.createValue((Boolean) value);
- else if (value instanceof Calendar)
- return valueFactory.createValue((Calendar) value);
- else if (value instanceof Date) {
- Calendar cal = new GregorianCalendar();
- cal.setTime((Date) value);
- return valueFactory.createValue(cal);
- } else if (value instanceof CharSequence)
- return valueFactory.createValue(value.toString());
- else if (value instanceof InputStream)
- return valueFactory.createValue((InputStream) value);
- else
- return null;
- }
-
- protected Class<?> classFromProperty(Property property)
- throws RepositoryException {
- switch (property.getType()) {
- case PropertyType.LONG:
- return Long.class;
- case PropertyType.DOUBLE:
- return Double.class;
- case PropertyType.STRING:
- return String.class;
- case PropertyType.BOOLEAN:
- return Boolean.class;
- case PropertyType.DATE:
- return Calendar.class;
- case PropertyType.NAME:
- return null;
- default:
- throw new ArgeoException("Cannot find class for property "
- + property + ", type="
- + PropertyType.nameFromValue(property.getType()));
- }
- }
-
- protected Object asObject(Value value, Class<?> propClass)
- throws RepositoryException {
- if (propClass.equals(Integer.class))
- return (int) value.getLong();
- else if (propClass.equals(Long.class))
- return value.getLong();
- else if (propClass.equals(Float.class))
- return (float) value.getDouble();
- else if (propClass.equals(Double.class))
- return value.getDouble();
- else if (propClass.equals(Boolean.class))
- return value.getBoolean();
- else if (CharSequence.class.isAssignableFrom(propClass))
- return value.getString();
- else if (InputStream.class.isAssignableFrom(propClass))
- return value.getStream();
- else if (Calendar.class.isAssignableFrom(propClass))
- return value.getDate();
- else if (Date.class.isAssignableFrom(propClass))
- return value.getDate().getTime();
- else
- return null;
- }
-
- protected Node findChildReference(Session session, BeanWrapper child)
- throws RepositoryException {
- if (child.isReadableProperty(uuidProperty)) {
- String childUuid = child.getPropertyValue(uuidProperty).toString();
- try {
- return session.getNodeByUUID(childUuid);
- } catch (ItemNotFoundException e) {
- if (strictUuidReference)
- throw new ArgeoException("No node found with uuid "
- + childUuid, e);
- }
- }
- return null;
- }
-
- protected Class<?> loadClass(String name) {
- // log.debug("Class loader: " + classLoader);
- try {
- return classLoader.loadClass(name);
- } catch (ClassNotFoundException e) {
- throw new ArgeoException("Cannot load class " + name, e);
- }
- }
-
- protected String propertyName(String name) {
- return name;
- }
-
- public void setVersioning(Boolean versioning) {
- this.versioning = versioning;
- }
-
- public void setUuidProperty(String uuidProperty) {
- this.uuidProperty = uuidProperty;
- }
-
- public void setClassProperty(String classProperty) {
- this.classProperty = classProperty;
- }
-
- public void setStrictUuidReference(Boolean strictUuidReference) {
- this.strictUuidReference = strictUuidReference;
- }
-
- public void setPrimaryNodeType(String primaryNodeType) {
- this.primaryNodeType = primaryNodeType;
- }
-
- public void setClassLoader(ClassLoader classLoader) {
- this.classLoader = classLoader;
- }
-
- public void setNodeMapperProvider(NodeMapperProvider nodeMapperProvider) {
- this.nodeMapperProvider = nodeMapperProvider;
- }
-
- public String getPrimaryNodeType() {
- return this.primaryNodeType;
- }
-
- public String getClassProperty() {
- return this.classProperty;
- }
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import java.util.Calendar;
-import java.util.StringTokenizer;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-
-public class JcrUtils {
- private final static Log log = LogFactory.getLog(JcrUtils.class);
-
- public static Node querySingleNode(Query query) {
- NodeIterator nodeIterator;
- try {
- QueryResult queryResult = query.execute();
- nodeIterator = queryResult.getNodes();
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot execute query " + query, e);
- }
- Node node;
- if (nodeIterator.hasNext())
- node = nodeIterator.nextNode();
- else
- return null;
-
- if (nodeIterator.hasNext())
- throw new ArgeoException("Query returned more than one node.");
- return node;
- }
-
- public static String removeForbiddenCharacters(String str) {
- return str.replace('[', '_').replace(']', '_').replace('/', '_')
- .replace('*', '_');
-
- }
-
- public static String parentPath(String path) {
- if (path.equals("/"))
- throw new ArgeoException("Root path '/' has no parent path");
- if (path.charAt(0) != '/')
- throw new ArgeoException("Path " + path + " must start with a '/'");
- String pathT = path;
- if (pathT.charAt(pathT.length() - 1) == '/')
- pathT = pathT.substring(0, pathT.length() - 2);
-
- int index = pathT.lastIndexOf('/');
- return pathT.substring(0, index);
- }
-
- public static String dateAsPath(Calendar cal) {
- StringBuffer buf = new StringBuffer(14);
- buf.append('Y').append(cal.get(Calendar.YEAR));// 5
- buf.append('/');// 1
- int month = cal.get(Calendar.MONTH) + 1;
- buf.append('M');
- if (month < 10)
- buf.append(0);
- buf.append(month);// 3
- buf.append('/');// 1
- int day = cal.get(Calendar.DAY_OF_MONTH);
- if (day < 10)
- buf.append(0);
- buf.append('D').append(day);// 3
- buf.append('/');// 1
- return buf.toString();
-
- }
-
- public static String hostAsPath(String host) {
- // TODO : inverse order of the elements (to have org/argeo/test IO
- // test/argeo/org
- return host.replace('.', '/');
- }
-
- public static String lastPathElement(String path) {
- if (path.charAt(path.length() - 1) == '/')
- throw new ArgeoException("Path " + path + " cannot end with '/'");
- int index = path.lastIndexOf('/');
- if (index < 0)
- throw new ArgeoException("Cannot find last path element for "
- + path);
- return path.substring(index + 1);
- }
-
- public static Node mkdirs(Session session, String path) {
- return mkdirs(session, path, null, false);
- }
-
- public static Node mkdirs(Session session, String path, String type,
- Boolean versioning) {
- try {
- if (path.equals('/'))
- return session.getRootNode();
-
- StringTokenizer st = new StringTokenizer(path, "/");
- StringBuffer current = new StringBuffer("/");
- Node currentNode = session.getRootNode();
- while (st.hasMoreTokens()) {
- String part = st.nextToken();
- current.append(part).append('/');
- if (!session.itemExists(current.toString())) {
- if (type != null)
- currentNode = currentNode.addNode(part, type);
- else
- currentNode = currentNode.addNode(part);
- if (versioning)
- currentNode.addMixin(ArgeoJcrConstants.MIX_VERSIONABLE);
- if (log.isTraceEnabled())
- log.debug("Added folder " + part + " as " + current);
- } else {
- currentNode = (Node) session.getItem(current.toString());
- }
- }
- session.save();
- return currentNode;
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot mkdirs " + path, e);
- }
- }
-
- public static void registerNamespaceSafely(Session session, String prefix,
- String uri) {
- try {
- registerNamespaceSafely(session.getWorkspace()
- .getNamespaceRegistry(), prefix, uri);
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot find namespace registry", e);
- }
- }
-
- public static void registerNamespaceSafely(NamespaceRegistry nr,
- String prefix, String uri) {
- try {
- String[] prefixes = nr.getPrefixes();
- for (String pref : prefixes)
- if (pref.equals(prefix)) {
- String registeredUri = nr.getURI(pref);
- if (!registeredUri.equals(uri))
- throw new ArgeoException("Prefix " + pref
- + " already registered for URI "
- + registeredUri
- + " which is different from provided URI "
- + uri);
- else
- return;// skip
- }
- nr.registerNamespace(prefix, uri);
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot register namespace " + uri
- + " under prefix " + prefix, e);
- }
- }
-
- /** Recursively outputs the contents of the given node. */
- public static void debug(Node node) throws RepositoryException {
- // First output the node path
- log.debug(node.getPath());
- // Skip the virtual (and large!) jcr:system subtree
- if (node.getName().equals(ArgeoJcrConstants.JCR_SYSTEM)) {
- return;
- }
-
- // Then the children nodes (recursive)
- NodeIterator it = node.getNodes();
- while (it.hasNext()) {
- Node childNode = it.nextNode();
- debug(childNode);
- }
-
- // Then output the properties
- PropertyIterator properties = node.getProperties();
- // log.debug("Property are : ");
-
- while (properties.hasNext()) {
- Property property = properties.nextProperty();
- if (property.getDefinition().isMultiple()) {
- // A multi-valued property, print all values
- Value[] values = property.getValues();
- for (int i = 0; i < values.length; i++) {
- log.debug(property.getPath() + "=" + values[i].getString());
- }
- } else {
- // A single-valued property
- log.debug(property.getPath() + "=" + property.getString());
- }
- }
-
- }
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.Session;
-
-public interface NodeMapper {
- public Object load(Node node);
-
- public void update(Node node, Object obj);
-
- public Node save(Session session, String path, Object obj);
-
- public void setNodeMapperProvider(NodeMapperProvider nmp);
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import javax.jcr.Node;
-
-/** Provides a node mapper relevant for this node. */
-public interface NodeMapperProvider {
-
- /**
- * Node Mapper is chosen regarding the Jcr path of the node parameter
- * @param Node node
- * @return the node mapper or null if no relevant node mapper can be found. */
- public NodeMapper findNodeMapper(Node node);
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.FactoryBean;
-
-public class ThreadBoundJcrSessionFactory implements FactoryBean,
- DisposableBean {
- private final static Log log = LogFactory
- .getLog(ThreadBoundJcrSessionFactory.class);
-
- private Repository repository;
- private List<Session> activeSessions = Collections
- .synchronizedList(new ArrayList<Session>());
-
- private ThreadLocal<Session> session = new ThreadLocal<Session>();
- private boolean destroying = false;
- private final Session proxiedSession;
-
- public ThreadBoundJcrSessionFactory() {
- Class<?>[] interfaces = { Session.class };
- proxiedSession = (Session) Proxy.newProxyInstance(getClass()
- .getClassLoader(), interfaces, new InvocationHandler() {
-
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Session threadSession = session.get();
- if (threadSession == null) {
- if ("logout".equals(method.getName()))// no need to login
- return Void.TYPE;
- threadSession = login();
- session.set(threadSession);
- }
-
- Object ret = method.invoke(threadSession, args);
- if ("logout".equals(method.getName())) {
- session.remove();
- if (!destroying)
- activeSessions.remove(threadSession);
- if (log.isTraceEnabled())
- log.trace("Logged out from JCR session "
- + threadSession + "; userId="
- + threadSession.getUserID());
- }
- return ret;
- }
- });
- }
-
- protected Session login() {
- try {
- Session sess = repository.login();
- if (log.isTraceEnabled())
- log.trace("Log in to JCR session " + sess + "; userId="
- + sess.getUserID());
- // Thread.dumpStack();
- activeSessions.add(sess);
- return sess;
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot log in to repository", e);
- }
- }
-
- public Object getObject() {
- return proxiedSession;
- }
-
- public void destroy() throws Exception {
- if (log.isDebugEnabled())
- log.debug("Cleaning up " + activeSessions.size()
- + " active JCR sessions...");
-
- destroying = true;
- for (Session sess : activeSessions) {
- sess.logout();
- }
- activeSessions.clear();
- }
-
- public Class<? extends Session> getObjectType() {
- return Session.class;
- }
-
- public boolean isSingleton() {
- return true;
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
-}
import org.apache.commons.io.FileUtils;
import org.apache.jackrabbit.core.TransientRepository;
import org.argeo.ArgeoException;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
public abstract class AbstractJcrTestCase extends TestCase {
private TransientRepository repository;
private Session session = null;
+ protected abstract File getRepositoryFile() throws Exception;
+
@Override
protected void setUp() throws Exception {
File homeDir = new File(System.getProperty("java.io.tmpdir"),
return session;
}
- protected File getRepositoryFile() throws Exception {
- Resource res = new ClassPathResource(
- "org/argeo/server/jackrabbit/repository-inMemory.xml");
- return res.getFile();
- }
-
protected Repository getRepository() {
return repository;
}
+++ /dev/null
-package org.argeo.server.jcr;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
-import javax.jcr.observation.ObservationManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-
-/** To be overridden */
-public class DefaultJcrListener implements EventListener {
- private final static Log log = LogFactory.getLog(DefaultJcrListener.class);
- private Session session;
- private Repository repository;
- private String path = "/";
- private Boolean deep = true;
- private String username = "demo";
- private String password = "demo";
-
- public void start() {
- try {
- addEventListener(session().getWorkspace().getObservationManager());
- if (log.isDebugEnabled())
- log.debug("Registered JCR event listener on " + path);
- } catch (Exception e) {
- throw new ArgeoException("Cannot register event listener", e);
- }
- }
-
- public void stop() {
- try {
- session().getWorkspace().getObservationManager()
- .removeEventListener(this);
- if (log.isDebugEnabled())
- log.debug("Unregistered JCR event listener on " + path);
- } catch (Exception e) {
- throw new ArgeoException("Cannot unregister event listener", e);
- }
- }
-
- /** Default is listen to all events */
- protected Integer getEvents() {
- return Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED
- | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
- }
-
- /** To be overidden */
- public void onEvent(EventIterator events) {
- while (events.hasNext()) {
- Event event = events.nextEvent();
- log.debug(event);
- }
- }
-
- /** To be overidden */
- protected void addEventListener(ObservationManager observationManager)
- throws RepositoryException {
- observationManager.addEventListener(this, getEvents(), path, deep,
- null, null, false);
- }
-
- protected Session session() {
- if (session == null)
- try {
- session = repository.login(new SimpleCredentials(username,
- password.toCharArray()));
- } catch (Exception e) {
- throw new ArgeoException("Cannot open session", e);
- }
- return session;
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public void setPath(String path) {
- this.path = path;
- }
-
- public void setDeep(Boolean deep) {
- this.deep = deep;
- }
-
-}
+++ /dev/null
-package org.argeo.server.jcr;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-
-import javax.activation.MimetypesFileTypeMap;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-import javax.jcr.version.VersionIterator;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.argeo.jcr.JcrUtils;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.core.io.Resource;
-
-public class JcrResourceAdapter implements InitializingBean, DisposableBean {
- private final static Log log = LogFactory.getLog(JcrResourceAdapter.class);
-
- private Repository repository;
-
- private String username;
- private String password;
-
- private Session session;
-
- private Boolean versioning = true;
- private String defaultEncoding = "UTF-8";
-
- // private String restoreBase = "/.restore";
-
- public void mkdirs(String path) {
- JcrUtils.mkdirs(session(), path, "nt:folder", versioning);
- }
-
- public void create(String path, Resource file, String mimeType) {
- try {
- create(path, file.getInputStream(), mimeType);
- } catch (IOException e) {
- throw new ArgeoException("Cannot read " + file, e);
- }
- }
-
- public void create(String path, InputStream in, String mimeType) {
- try {
- if (session().itemExists(path)) {
- throw new ArgeoException("Node " + path + " already exists.");
- }
-
- int index = path.lastIndexOf('/');
- String parentPath = path.substring(0, index);
- if (parentPath.equals(""))
- parentPath = "/";
- String fileName = path.substring(index + 1);
- if (!session().itemExists(parentPath))
- throw new ArgeoException("Parent folder of node " + path
- + " does not exist: " + parentPath);
-
- Node folderNode = (Node) session().getItem(parentPath);
- Node fileNode = folderNode.addNode(fileName, "nt:file");
-
- Node contentNode = fileNode.addNode("jcr:content", "nt:resource");
- if (mimeType != null)
- contentNode.setProperty("jcr:mimeType", mimeType);
- contentNode.setProperty("jcr:encoding", defaultEncoding);
- contentNode.setProperty("jcr:data", in);
- Calendar lastModified = Calendar.getInstance();
- // lastModified.setTimeInMillis(file.lastModified());
- contentNode.setProperty("jcr:lastModified", lastModified);
- // resNode.addMixin("mix:referenceable");
-
- if (versioning)
- fileNode.addMixin("mix:versionable");
-
- session().save();
-
- if (versioning)
- fileNode.checkin();
-
- if (log.isDebugEnabled())
- log.debug("Created " + path);
- } catch (Exception e) {
- throw new ArgeoException("Cannot create node for " + path, e);
- }
-
- }
-
- public void update(String path, Resource file) {
- try {
- update(path, file.getInputStream());
- } catch (IOException e) {
- throw new ArgeoException("Cannot read " + file, e);
- }
- }
-
- public void update(String path, InputStream in) {
- try {
-
- if (!session().itemExists(path)) {
- String type = new MimetypesFileTypeMap()
- .getContentType(FilenameUtils.getName(path));
- create(path, in, type);
- return;
- }
-
- Node fileNode = (Node) session().getItem(path);
- Node contentNode = fileNode.getNode("jcr:content");
- fileNode.checkout();
- contentNode.setProperty("jcr:data", in);
- Calendar lastModified = Calendar.getInstance();
- // lastModified.setTimeInMillis(file.lastModified());
- contentNode.setProperty("jcr:lastModified", lastModified);
-
- session().save();
- fileNode.checkin();
-
- if (log.isDebugEnabled())
- log.debug("Updated " + path);
- } catch (Exception e) {
- throw new ArgeoException("Cannot update node " + path, e);
- }
- }
-
- public List<Calendar> listVersions(String path) {
- if (!versioning)
- throw new ArgeoException("Versioning is not activated");
-
- try {
- List<Calendar> versions = new ArrayList<Calendar>();
- Node fileNode = (Node) session().getItem(path);
- VersionHistory history = fileNode.getVersionHistory();
- for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
- Version version = (Version) it.next();
- versions.add(version.getCreated());
- if (log.isTraceEnabled()) {
- log.debug(version);
- // debug(version);
- }
- }
- return versions;
- } catch (Exception e) {
- throw new ArgeoException("Cannot list version of node " + path, e);
- }
- }
-
- public InputStream retrieve(String path) {
- try {
- Node node = (Node) session().getItem(path + "/jcr:content");
- Property property = node.getProperty("jcr:data");
- return property.getStream();
- } catch (Exception e) {
- throw new ArgeoException("Cannot retrieve " + path, e);
- }
- }
-
- public synchronized InputStream retrieve(String path, Integer revision) {
- if (!versioning)
- throw new ArgeoException("Versioning is not activated");
-
- try {
- Node fileNode = (Node) session().getItem(path);
- VersionHistory history = fileNode.getVersionHistory();
- int count = 0;
- Version version = null;
- for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
- version = (Version) it.next();
- if (count == revision + 1) {
- InputStream in = fromVersion(version);
- if (log.isDebugEnabled())
- log.debug("Retrieved " + path + " at revision "
- + revision);
- return in;
- }
- count++;
- }
- } catch (Exception e) {
- throw new ArgeoException("Cannot retrieve version " + revision
- + " of " + path, e);
- }
-
- throw new ArgeoException("Version " + revision
- + " does not exist for node " + path);
- }
-
- protected InputStream fromVersion(Version version)
- throws RepositoryException {
- Node frozenNode = version.getNode("jcr:frozenNode");
- InputStream in = frozenNode.getNode("jcr:content").getProperty(
- "jcr:data").getStream();
- return in;
- }
-
- protected Session session() {
- return session;
- }
-
- public void afterPropertiesSet() throws Exception {
- session = repository.login(new SimpleCredentials(username, password
- .toCharArray()));
- }
-
- public void destroy() throws Exception {
- session.logout();
- }
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public void setVersioning(Boolean versioning) {
- this.versioning = versioning;
- }
-
- public void setDefaultEncoding(String defaultEncoding) {
- this.defaultEncoding = defaultEncoding;
- }
-
- protected String fill(Integer number) {
- int size = 4;
- String str = number.toString();
- for (int i = str.length(); i < size; i++) {
- str = "0" + str;
- }
- return str;
- }
-}
+++ /dev/null
-package org.argeo.server.jcr.mvc;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Item;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.query.RowIterator;
-
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.WebRequest;
-
-@Controller
-public class JcrBrowserController implements JcrMvcConstants {
-
- @RequestMapping("/getJcrItem.*")
- public Item getJcrItem(WebRequest webRequest,
- @RequestParam("path") String path) throws RepositoryException {
- return ((Session) webRequest.getAttribute(REQUEST_ATTR_SESSION,
- RequestAttributes.SCOPE_REQUEST)).getItem(path);
- }
-
- @RequestMapping("/queryJcrNodes.*")
- public List<String> queryJcrNodes(WebRequest webRequest,
- @RequestParam("statement") String statement,
- @RequestParam("language") String language)
- throws RepositoryException {
- Session session = ((Session) webRequest.getAttribute(
- REQUEST_ATTR_SESSION, RequestAttributes.SCOPE_REQUEST));
- Query query = session.getWorkspace().getQueryManager().createQuery(
- statement, language);
- NodeIterator nit = query.execute().getNodes();
- List<String> paths = new ArrayList<String>();
- while (nit.hasNext()) {
- paths.add(nit.nextNode().getPath());
- }
- return paths;
- }
-
- @RequestMapping("/queryJcrTable.*")
- public List<List<String>> queryJcrTable(WebRequest webRequest,
- @RequestParam("statement") String statement,
- @RequestParam("language") String language)
- throws RepositoryException {
- Session session = ((Session) webRequest.getAttribute(
- REQUEST_ATTR_SESSION, RequestAttributes.SCOPE_REQUEST));
- Query query = session.getWorkspace().getQueryManager().createQuery(
- statement, language);
- QueryResult queryResult = query.execute();
- List<List<String>> results = new ArrayList<List<String>>();
- results.add(Arrays.asList(queryResult.getColumnNames()));
- RowIterator rit = queryResult.getRows();
-
- while (rit.hasNext()) {
- Row row = rit.nextRow();
- List<String> lst = new ArrayList<String>();
- for (Value value : row.getValues()) {
- lst.add(value.getString());
- }
- }
- return results;
- }
-}
+++ /dev/null
-package org.argeo.server.jcr.mvc;
-
-import java.util.List;
-import java.util.StringTokenizer;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.fileupload.FileItem;
-import org.apache.commons.fileupload.FileItemFactory;
-import org.apache.commons.fileupload.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.server.ServerAnswer;
-import org.argeo.server.jcr.JcrResourceAdapter;
-import org.argeo.server.mvc.MvcConstants;
-import org.springframework.core.io.ByteArrayResource;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-@Controller
-public class JcrManagerController implements MvcConstants {
- private final static Log log = LogFactory
- .getLog(JcrManagerController.class);
-
- private JcrResourceAdapter resourceAdapter;
-
- // Create a factory for disk-based file items
- private FileItemFactory factory = new DiskFileItemFactory();
-
- // Create a new file upload handler
- private ServletFileUpload upload = new ServletFileUpload(factory);
-
- @SuppressWarnings("unchecked")
- @RequestMapping("/upload/**")
- @ModelAttribute(ANSWER_MODEL_KEY_AS_HTML)
- public ServerAnswer upload(HttpServletRequest request,
- HttpServletResponse response) throws Exception {
- // Parse the request
- List<FileItem> items = upload.parseRequest(request);
-
- byte[] arr = null;
- for (FileItem item : items) {
- if (!item.isFormField()) {
- arr = item.get();
- break;
- }
- }
-
- ByteArrayResource res = new ByteArrayResource(arr);
- // String pathInfo = request.getPathInfo();
-
- StringBuffer path = new StringBuffer("/");
- StringTokenizer st = new StringTokenizer(request.getPathInfo(), "/");
- st.nextToken();// skip /upload/
- while (st.hasMoreTokens()) {
- String token = st.nextToken();
- if (!st.hasMoreTokens()) {
- resourceAdapter.mkdirs(path.toString());
- path.append(token);
- } else {
- path.append(token).append('/');
- }
- }
- // String path = '/' + pathInfo.substring(1).substring(
- // pathInfo.indexOf('/'));
- if (log.isDebugEnabled())
- log.debug("Upload to " + path);
- resourceAdapter.update(path.toString(), res);
- return ServerAnswer.ok("File " + path + " imported");
- }
-
- public void setResourceAdapter(JcrResourceAdapter resourceAdapter) {
- this.resourceAdapter = resourceAdapter;
- }
-
-}
+++ /dev/null
-package org.argeo.server.jcr.mvc;
-
-public interface JcrMvcConstants {
- public final static String REQUEST_ATTR_SESSION = "jcrSession";
-}
+++ /dev/null
-package org.argeo.server.jcr.mvc;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.argeo.ArgeoException;
-import org.argeo.server.ServerSerializer;
-import org.springframework.xml.dom.DomContentHandler;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-public class JcrXmlServerSerializer implements ServerSerializer {
- private String contentTypeCharset = "UTF-8";
-
- private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
- .newInstance();
- private final TransformerFactory transformerFactory = TransformerFactory
- .newInstance();
-
- public void serialize(Object obj, HttpServletRequest request,
- HttpServletResponse response) {
- if (!(obj instanceof Node))
- throw new ArgeoException("Only " + Node.class + " is supported");
-
- String noRecurseStr = request.getParameter("noRecurse");
- boolean noRecurse = noRecurseStr != null && noRecurseStr.equals("true");
-
- String depthStr = request.getParameter("depth");
- String downloadStr = request.getParameter("download");
-
- Node node = (Node) obj;
-
- try {
- String contentType = "text/xml;charset=" + contentTypeCharset;
- // download case
- if (downloadStr != null && downloadStr.equals("true")) {
- String fileName = node.getName().replace(':', '_') + ".xml";
- contentType = contentType + ";name=\"" + fileName + "\"";
- response.setHeader("Content-Disposition",
- "attachment; filename=\"" + fileName + "\"");
- response.setHeader("Expires", "0");
- response
- .setHeader("Cache-Control", "no-cache, must-revalidate");
- response.setHeader("Pragma", "no-cache");
- }
-
- response.setContentType(contentType);
- if (depthStr == null) {
- node.getSession().exportDocumentView(node.getPath(),
- response.getOutputStream(), true, noRecurse);
- } else {
- int depth = Integer.parseInt(depthStr);
- Document document = documentBuilderFactory.newDocumentBuilder()
- .newDocument();
- serializeLevelToDom(node, document, 0, depth);
- Transformer transformer = transformerFactory.newTransformer();
- transformer.transform(new DOMSource(document),
- new StreamResult(response.getOutputStream()));
- }
- } catch (Exception e) {
- throw new ArgeoException("Cannot serialize " + node, e);
- }
- }
-
- protected void serializeLevelToDom(Node currentJcrNode,
- org.w3c.dom.Node currentDomNode, int currentDepth, int targetDepth)
- throws RepositoryException, SAXException {
- DomContentHandler domContentHandler = new DomContentHandler(
- currentDomNode);
- currentJcrNode.getSession().exportDocumentView(
- currentJcrNode.getPath(), domContentHandler, true, true);
-
- if (currentDepth == targetDepth)
- return;
-
- // TODO: filter
- NodeIterator nit = currentJcrNode.getNodes();
- while (nit.hasNext()) {
- Node nextJcrNode = nit.nextNode();
- org.w3c.dom.Node nextDomNode;
- if (currentDomNode instanceof Document)
- nextDomNode = ((Document) currentDomNode).getDocumentElement();
- else {
- String name = currentJcrNode.getName();
- NodeList nodeList = ((Element) currentDomNode)
- .getElementsByTagName(name);
- if (nodeList.getLength() < 1)
- throw new ArgeoException("No elment named " + name
- + " under " + currentDomNode);
- // we know it is the last one added
- nextDomNode = nodeList.item(nodeList.getLength() - 1);
- }
- // recursive call
- serializeLevelToDom(nextJcrNode, nextDomNode, currentDepth + 1,
- targetDepth);
- }
- }
-
- public void setContentTypeCharset(String contentTypeCharset) {
- this.contentTypeCharset = contentTypeCharset;
- }
-
-}
+++ /dev/null
-package org.argeo.server.jcr.mvc;
-
-import javax.jcr.Session;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.ui.ModelMap;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.WebRequest;
-import org.springframework.web.context.request.WebRequestInterceptor;
-
-public class OpenSessionInViewJcrInterceptor implements WebRequestInterceptor,
- JcrMvcConstants {
- private final static Log log = LogFactory
- .getLog(OpenSessionInViewJcrInterceptor.class);
-
- private Session session;
-
- public void preHandle(WebRequest request) throws Exception {
- if (log.isTraceEnabled())
- log.trace("preHandle: " + request);
- // Authentication auth = SecurityContextHolder.getContext()
- // .getAuthentication();
- // if (auth != null)
- // log.debug("auth=" + auth + ", authenticated="
- // + auth.isAuthenticated() + ", name=" + auth.getName());
- // else
- // log.debug("No auth");
-
- // FIXME: find a safer way to initialize
- // FIXME: not really needed to initialize here
- // session.getRepository();
- request.setAttribute(REQUEST_ATTR_SESSION, session,
- RequestAttributes.SCOPE_REQUEST);
- }
-
- public void postHandle(WebRequest request, ModelMap model) throws Exception {
- // if (log.isDebugEnabled())
- // log.debug("postHandle: " + request);
- }
-
- public void afterCompletion(WebRequest request, Exception ex)
- throws Exception {
- if (log.isTraceEnabled())
- log.trace("afterCompletion: " + request);
- // FIXME: only close session that were open
- session.logout();
- }
-
- public void setSession(Session session) {
- this.session = session;
- }
-
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class CollectionsObject {
- private String id;
- private String label;
- private SimpleObject simpleObject;
- private List<String> stringList = new ArrayList<String>();
- private Map<String, Float> floatMap = new HashMap<String, Float>();
- private Map<SimpleObject, String> objectMap = new HashMap<SimpleObject, String>();
- private Map<String, Map<String, String>> mapOfMaps = new HashMap<String, Map<String, String>>();
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getLabel() {
- return label;
- }
-
- public void setLabel(String label) {
- this.label = label;
- }
-
- public SimpleObject getSimpleObject() {
- return simpleObject;
- }
-
- public void setSimpleObject(SimpleObject simpleObject) {
- this.simpleObject = simpleObject;
- }
-
- public List<String> getStringList() {
- return stringList;
- }
-
- public void setStringList(List<String> stringList) {
- this.stringList = stringList;
- }
-
- public Map<String, Float> getFloatMap() {
- return floatMap;
- }
-
- public void setFloatMap(Map<String, Float> floatMap) {
- this.floatMap = floatMap;
- }
-
- public Map<SimpleObject, String> getObjectMap() {
- return objectMap;
- }
-
- public void setObjectMap(Map<SimpleObject, String> objectMap) {
- this.objectMap = objectMap;
- }
-
- public Map<String, Map<String, String>> getMapOfMaps() {
- return mapOfMaps;
- }
-
- public void setMapOfMaps(Map<String, Map<String, String>> mapOfMaps) {
- this.mapOfMaps = mapOfMaps;
- }
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import javax.jcr.Node;
-
-import org.argeo.server.jackrabbit.unit.AbstractJcrTestCase;
-
-public class MapperTest extends AbstractJcrTestCase {
- public void testSimpleObject() throws Exception {
- SimpleObject mySo = new SimpleObject();
- mySo.setInteger(100);
- mySo.setString("hello world");
-
- OtherObject oo1 = new OtherObject();
- oo1.setKey("someKey");
- oo1.setValue("stringValue");
- mySo.setOtherObject(oo1);
-
- OtherObject oo2 = new OtherObject();
- oo2.setKey("anotherSimpleObject");
- oo2.setValue(new SimpleObject());
- mySo.setAnotherObject(oo2);
-
- BeanNodeMapper bnm = new BeanNodeMapper();
-
- Node node = bnm.save(session(), mySo);
- session().save();
- JcrUtils.debug(node);
- }
-}
+++ /dev/null
-package org.argeo.jcr;
-
-public class OtherObject {
- private String key;
- private Object value;
-
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public Object getValue() {
- return value;
- }
-
- public void setValue(Object value) {
- this.value = value;
- }
-}
+++ /dev/null
-package org.argeo.jcr;
-
-import java.util.UUID;
-
-public class SimpleObject {
- private String string;
- private String uuid = UUID.randomUUID().toString();
- private Integer integer;
- private OtherObject otherObject;
- private OtherObject anotherObject;
-
- public String getString() {
- return string;
- }
-
- public void setString(String sting) {
- this.string = sting;
- }
-
- public Integer getInteger() {
- return integer;
- }
-
- public void setInteger(Integer integer) {
- this.integer = integer;
- }
-
- public OtherObject getOtherObject() {
- return otherObject;
- }
-
- public void setOtherObject(OtherObject otherObject) {
- this.otherObject = otherObject;
- }
-
- public OtherObject getAnotherObject() {
- return anotherObject;
- }
-
- public void setAnotherObject(OtherObject anotherObject) {
- this.anotherObject = anotherObject;
- }
-
- @Override
- public boolean equals(Object obj) {
- return string.equals(((SimpleObject) obj).string);
- }
-
- @Override
- public int hashCode() {
- return string.hashCode();
- }
-
- public void setUuid(String uuid) {
- this.uuid = uuid;
- }
-
- public String getUuid() {
- return uuid;
- }
-
-}
+++ /dev/null
-package org.argeo.server.jcr;
-
-import java.io.InputStream;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.List;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.server.jackrabbit.unit.AbstractJcrTestCase;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-
-public class JcrResourceAdapterTest extends AbstractJcrTestCase {
- private static SimpleDateFormat sdf = new SimpleDateFormat(
- "yyyyMMdd:hhmmss.SSS");
-
- private final static Log log = LogFactory
- .getLog(JcrResourceAdapterTest.class);
-
- private JcrResourceAdapter jra;
-
- public void testCreate() throws Exception {
- String basePath = "/test/subdir";
- jra.mkdirs(basePath);
- Resource res = new ClassPathResource("org/argeo/server/jcr/dummy00.xls");
- String filePath = basePath + "/dummy.xml";
- jra.create(filePath, res, "application/vnd.ms-excel");
- InputStream in = jra.retrieve(filePath);
- assertTrue(IOUtils.contentEquals(res.getInputStream(), in));
- }
-
- public void testVersioning() throws Exception {
- String basePath = "/test/versions";
- jra.mkdirs(basePath);
- String filePath = basePath + "/dummy.xml";
- Resource res00 = new ClassPathResource(
- "org/argeo/server/jcr/dummy00.xls");
- jra.create(filePath, res00, "application/vnd.ms-excel");
- Resource res01 = new ClassPathResource(
- "org/argeo/server/jcr/dummy01.xls");
- jra.update(filePath, res01);
- Resource res02 = new ClassPathResource(
- "org/argeo/server/jcr/dummy02.xls");
- jra.update(filePath, res02);
-
- List<Calendar> versions = jra.listVersions(filePath);
- log.debug("Versions of " + filePath);
- int count = 0;
- for (Calendar version : versions) {
- log.debug(" " + (count == 0 ? "base" : count - 1) + "\t"
- + sdf.format(version.getTime()));
- count++;
- }
-
- assertEquals(4, versions.size());
-
- InputStream in = jra.retrieve(filePath, 1);
- assertTrue(IOUtils.contentEquals(res01.getInputStream(), in));
- in = jra.retrieve(filePath, 0);
- assertTrue(IOUtils.contentEquals(res00.getInputStream(), in));
- in = jra.retrieve(filePath, 2);
- assertTrue(IOUtils.contentEquals(res02.getInputStream(), in));
- Resource res03 = new ClassPathResource(
- "org/argeo/server/jcr/dummy03.xls");
- jra.update(filePath, res03);
- in = jra.retrieve(filePath, 1);
- assertTrue(IOUtils.contentEquals(res01.getInputStream(), in));
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- jra = new JcrResourceAdapter();
- jra.setRepository(getRepository());
- jra.setUsername("demo");
- jra.setPassword("demo");
- jra.afterPropertiesSet();
- }
-
- @Override
- protected void tearDown() throws Exception {
- jra.destroy();
- super.tearDown();
- }
-
-}
+++ /dev/null
-log4j.rootLogger=WARN, console
-
-## Levels
-log4j.logger.org.argeo=DEBUG
-log4j.logger.org.apache.jackrabbit=OFF
-
-## Appenders
-# console is set to be a ConsoleAppender.
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-
-# console uses PatternLayout.
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c%n
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>\r
-<beans xmlns="http://www.springframework.org/schema/beans"\r
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
-\r
- <bean\r
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">\r
- <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />\r
- <property name="ignoreUnresolvablePlaceholders" value="true" />\r
- </bean>\r
-\r
- <bean id="nodeMapperProvider" class="org.argeo.slc.jcr.dao.SlcNodeMapperProvider"\r
- init-method="init">\r
- <property name="defaultNodeMapper" ref="nodeMapper" />\r
- <property name="treeTestResultNodeMapper" ref="treeTestResultNodeMapper" />\r
- </bean>\r
-\r
- <bean id="nodeMapper" class="org.argeo.jcr.BeanNodeMapper">\r
- </bean>\r
-\r
- <bean id="treeTestResultNodeMapper" class="org.argeo.slc.jcr.dao.TreeTestResultNodeMapper">\r
- </bean>\r
-\r
- <bean id="argeo.jcr.session.inMemory" factory-bean="argeo.jcr.repository.inMemory"\r
- factory-method="login" destroy-method="logout">\r
- <constructor-arg>\r
- <bean class="javax.jcr.SimpleCredentials">\r
- <constructor-arg value="demo" />\r
- <constructor-arg value="demo" />\r
- </bean>\r
- </constructor-arg>\r
- </bean>\r
-\r
- <bean id="argeo.jcr.repository.inMemory" class="org.argeo.server.jackrabbit.JackrabbitContainer">\r
- <property name="homeDirectory" value="${java.io.tmpdir}/jackrabbit-slc-unit" />\r
- <property name="configuration"\r
- value="classpath:/org/argeo/server/jackrabbit/repository-inMemory.xml" />\r
- </bean>\r
-\r
-</beans>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
- "http://jackrabbit.apache.org/dtd/repository-1.6.dtd">
-<!-- Example Repository Configuration File
- Used by
- - org.apache.jackrabbit.core.config.RepositoryConfigTest.java
- -
--->
-<Repository>
- <!--
- virtual file system where the repository stores global state
- (e.g. registered namespaces, custom node types, etc.)
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
- <param name="path" value="${rep.home}/repository"/>
- </FileSystem>
-
- <!--
- security configuration
- -->
- <Security appName="Jackrabbit">
- <!--
- security manager:
- class: FQN of class implementing the JackrabbitSecurityManager interface
- -->
- <SecurityManager class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager" workspaceName="security">
- <!--
- workspace access:
- class: FQN of class implementing the WorkspaceAccessManager interface
- -->
- <!-- <WorkspaceAccessManager class="..."/> -->
- <!-- <param name="config" value="${rep.home}/security.xml"/> -->
- </SecurityManager>
-
- <!--
- access manager:
- class: FQN of class implementing the AccessManager interface
- -->
- <AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
- <!-- <param name="config" value="${rep.home}/access.xml"/> -->
- </AccessManager>
-
- <LoginModule class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
- <!--
- anonymous user name ('anonymous' is the default value)
- -->
- <param name="anonymousId" value="anonymous"/>
- <!--
- administrator user id (default value if param is missing is 'admin')
- -->
- <param name="adminId" value="admin"/>
- </LoginModule>
- </Security>
-
- <!--
- location of workspaces root directory and name of default workspace
- -->
- <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
- <!--
- workspace configuration template:
- used to create the initial workspace if there's no workspace yet
- -->
- <Workspace name="${wsp.name}">
- <!--
- virtual file system of the workspace:
- class: FQN of class implementing the FileSystem interface
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
- <param name="path" value="${wsp.home}"/>
- </FileSystem>
- <!--
- persistence manager of the workspace:
- class: FQN of class implementing the PersistenceManager interface
- -->
- <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
- <param name="url" value="jdbc:derby:memory:db;create=true"/>
- <param name="schemaObjectPrefix" value="${wsp.name}_"/>
- </PersistenceManager>
- <!--
- Search index and the file system it uses.
- class: FQN of class implementing the QueryHandler interface
- -->
- <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
- <param name="path" value="${wsp.home}/index"/>
- <param name="extractorPoolSize" value="2"/>
- <param name="supportHighlighting" value="true"/>
- </SearchIndex>
- </Workspace>
-
- <!--
- Configures the versioning
- -->
- <Versioning rootPath="${rep.home}/version">
- <!--
- Configures the filesystem to use for versioning for the respective
- persistence manager
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
- <param name="path" value="${rep.home}/version" />
- </FileSystem>
-
- <!--
- Configures the persistence manager to be used for persisting version state.
- Please note that the current versioning implementation is based on
- a 'normal' persistence manager, but this could change in future
- implementations.
- -->
- <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
- <param name="url" value="jdbc:derby:memory:version;create=true"/>
- <param name="schemaObjectPrefix" value="version_"/>
- </PersistenceManager>
- </Versioning>
-
- <!--
- Search index for content that is shared repository wide
- (/jcr:system tree, contains mainly versions)
- -->
- <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
- <param name="path" value="${rep.home}/repository/index"/>
- <param name="extractorPoolSize" value="2"/>
- <param name="supportHighlighting" value="true"/>
- </SearchIndex>
-</Repository>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="target/classes"/>
Manifest-Version: 1.0\r
Created-By: 1.5.0_16 (Sun Microsystems Inc.)\r
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt\r
+Import-Package: javax.activation;version="1.1",javax.jcr;version="1.0"\r
+ ,javax.jcr.nodetype;version="1.0",javax.jcr.observation;version="1.0"\r
+ ,javax.jcr.query;version="1.0",javax.jcr.version;version="1.0",javax.\r
+ servlet;version="2.5",javax.servlet.http;version="2.5",javax.xml.pars\r
+ ers,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.s\r
+ tream,org.apache.commons.fileupload;version="1.2",org.apache.commons.\r
+ fileupload.disk;version="1.2",org.apache.commons.fileupload.servlet;v\r
+ ersion="1.2",org.apache.commons.io;version="1.4",org.apache.commons.l\r
+ ogging;version="1.1",org.argeo;version="0.1",org.argeo.jcr;version="0\r
+ .1",org.argeo.server;version="0.1",org.argeo.server.jcr;version="0.1"\r
+ ,org.argeo.server.jcr.mvc;version="0.1",org.argeo.server.mvc;version=\r
+ "0.1",org.springframework.beans;version="2.5",org.springframework.bea\r
+ ns.factory;version="2.5",org.springframework.core.io;version="2.5",or\r
+ g.springframework.stereotype;version="2.5",org.springframework.ui;ver\r
+ sion="2.5",org.springframework.web.bind.annotation;version="2.5",org.\r
+ springframework.web.context.request;version="2.5",org.springframework\r
+ .xml.dom;version="1.5",org.w3c.dom,org.xml.sax\r
Bundle-RequiredExecutionEnvironment: J2SE-1.5\r
-Bundle-Version: 0.1.3.SNAPSHOT-r3539\r
+Export-Package: org.argeo.jcr;uses:="org.springframework.beans,javax.j\r
+ cr,org.argeo,javax.jcr.query,org.apache.commons.logging,javax.jcr.nod\r
+ etype,org.springframework.beans.factory";version="0.1.3.SNAPSHOT-r354\r
+ 0",org.argeo.server.jcr.mvc;uses:="org.springframework.web.context.re\r
+ quest,org.springframework.web.bind.annotation,org.springframework.ste\r
+ reotype,javax.jcr.query,javax.jcr,javax.servlet.http,org.apache.commo\r
+ ns.logging,org.argeo.server,org.apache.commons.fileupload,org.argeo.s\r
+ erver.jcr,org.springframework.core.io,org.apache.commons.fileupload.s\r
+ ervlet,org.argeo.server.mvc,org.apache.commons.fileupload.disk,org.xm\r
+ l.sax,org.w3c.dom,org.argeo,javax.xml.transform,javax.xml.transform.d\r
+ om,javax.servlet,org.springframework.xml.dom,javax.xml.parsers,javax.\r
+ xml.transform.stream,org.springframework.ui";version="0.1.3.SNAPSHOT-\r
+ r3540",org.argeo.server.jcr;uses:="javax.jcr.observation,org.apache.c\r
+ ommons.logging,javax.jcr,org.argeo,javax.activation,org.argeo.jcr,org\r
+ .springframework.core.io,org.apache.commons.io,javax.jcr.version,org.\r
+ springframework.beans.factory";version="0.1.3.SNAPSHOT-r3540"\r
+Bundle-Version: 0.1.3.SNAPSHOT-r3540\r
Bundle-Name: Commons Server JCR\r
Bundle-DocURL: http://www.argeo.org\r
Bundle-ManifestVersion: 2\r
Bundle-Vendor: Argeo\r
-Fragment-Host: org.argeo.dep.osgi.jackrabbit\r
Bundle-SymbolicName: org.argeo.server.jcr\r
Tool: Bnd-0.0.357\r
\r
-source.. = src/main/java/
+source.. = src/main/java/,\
+ src/test/java/,\
+ src/test/resources/
output.. = target/classes/
bin.includes = META-INF/,\
.
+additional.bundles = org.argeo.server.jackrabbit,\
+ com.springsource.slf4j.api,\
+ com.springsource.slf4j.log4j,\
+ com.springsource.org.apache.log4j,\
+ com.springsource.org.apache.commons.collections,\
+ com.springsource.edu.oswego.cs.dl.util.concurrent,\
+ com.springsource.org.apache.derby,\
+ com.springsource.org.apache.lucene,\
+ com.springsource.junit
+
<version>${version.maven-bundle-plugin}</version>
<configuration>
<instructions>
- <Fragment-Host>org.argeo.dep.osgi.jackrabbit</Fragment-Host>
<Export-Package>
org.argeo.jcr.*,
org.argeo.server.jcr.*
<version>0.1.3-SNAPSHOT</version>
</dependency>
- <!-- Jack Rabbit -->
+ <!-- JCR -->
<dependency>
- <groupId>org.argeo.dep.osgi</groupId>
- <artifactId>org.argeo.dep.osgi.jackrabbit</artifactId>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>com.springsource.javax.servlet</artifactId>
- </dependency>
-
- <!-- Apache Commons -->
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>com.springsource.org.apache.commons.io</artifactId>
- </dependency>
-
- <dependency>
- <groupId>javax.activation</groupId>
- <artifactId>com.springsource.javax.activation</artifactId>
+ <groupId>javax.jcr</groupId>
+ <artifactId>com.springsource.javax.jcr</artifactId>
</dependency>
<!-- Spring -->
<artifactId>org.springframework.xml</artifactId>
</dependency>
+ <dependency>
+ <groupId>javax.activation</groupId>
+ <artifactId>com.springsource.javax.activation</artifactId>
+ </dependency>
+
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
</dependency>
<!-- TEST -->
+ <dependency>
+ <groupId>org.argeo.commons.server</groupId>
+ <artifactId>org.argeo.server.jackrabbit</artifactId>
+ <version>0.1.3-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.argeo.commons.basic</groupId>
<artifactId>org.argeo.support.junit</artifactId>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
+ "http://jackrabbit.apache.org/dtd/repository-1.6.dtd">
+<!-- Example Repository Configuration File
+ Used by
+ - org.apache.jackrabbit.core.config.RepositoryConfigTest.java
+ -
+-->
+<Repository>
+ <!--
+ virtual file system where the repository stores global state
+ (e.g. registered namespaces, custom node types, etc.)
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/repository"/>
+ </FileSystem>
+
+ <!--
+ security configuration
+ -->
+ <Security appName="Jackrabbit">
+ <!--
+ security manager:
+ class: FQN of class implementing the JackrabbitSecurityManager interface
+ -->
+ <SecurityManager class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager" workspaceName="security">
+ <!--
+ workspace access:
+ class: FQN of class implementing the WorkspaceAccessManager interface
+ -->
+ <!-- <WorkspaceAccessManager class="..."/> -->
+ <!-- <param name="config" value="${rep.home}/security.xml"/> -->
+ </SecurityManager>
+
+ <!--
+ access manager:
+ class: FQN of class implementing the AccessManager interface
+ -->
+ <AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
+ <!-- <param name="config" value="${rep.home}/access.xml"/> -->
+ </AccessManager>
+
+ <LoginModule class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
+ <!--
+ anonymous user name ('anonymous' is the default value)
+ -->
+ <param name="anonymousId" value="anonymous"/>
+ <!--
+ administrator user id (default value if param is missing is 'admin')
+ -->
+ <param name="adminId" value="admin"/>
+ </LoginModule>
+ </Security>
+
+ <!--
+ location of workspaces root directory and name of default workspace
+ -->
+ <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
+ <!--
+ workspace configuration template:
+ used to create the initial workspace if there's no workspace yet
+ -->
+ <Workspace name="${wsp.name}">
+ <!--
+ virtual file system of the workspace:
+ class: FQN of class implementing the FileSystem interface
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${wsp.home}"/>
+ </FileSystem>
+ <!--
+ persistence manager of the workspace:
+ class: FQN of class implementing the PersistenceManager interface
+ -->
+ <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+ <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
+ <param name="schemaObjectPrefix" value="${wsp.name}_"/>
+ </PersistenceManager>
+ <!--
+ Search index and the file system it uses.
+ class: FQN of class implementing the QueryHandler interface
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${wsp.home}/index"/>
+ <param name="extractorPoolSize" value="2"/>
+ <param name="supportHighlighting" value="true"/>
+ </SearchIndex>
+ </Workspace>
+
+ <!--
+ Configures the versioning
+ -->
+ <Versioning rootPath="${rep.home}/version">
+ <!--
+ Configures the filesystem to use for versioning for the respective
+ persistence manager
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/version" />
+ </FileSystem>
+
+ <!--
+ Configures the persistence manager to be used for persisting version state.
+ Please note that the current versioning implementation is based on
+ a 'normal' persistence manager, but this could change in future
+ implementations.
+ -->
+ <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+ <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
+ <param name="schemaObjectPrefix" value="version_"/>
+ </PersistenceManager>
+ </Versioning>
+
+ <!--
+ Search index for content that is shared repository wide
+ (/jcr:system tree, contains mainly versions)
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index"/>
+ <param name="extractorPoolSize" value="2"/>
+ <param name="supportHighlighting" value="true"/>
+ </SearchIndex>
+</Repository>
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.jcr;
+
+/**
+ * Copied from org.apache.jackrabbit.JcrConstants v1.6.0 in order to avoid a
+ * dependency to Jackrabbit.
+ */
+public interface ArgeoJcrConstants {
+ /**
+ * jcr:autoCreated
+ */
+ public static final String JCR_AUTOCREATED = "jcr:autoCreated";
+ /**
+ * jcr:baseVersion
+ */
+ public static final String JCR_BASEVERSION = "jcr:baseVersion";
+ /**
+ * jcr:child
+ */
+ public static final String JCR_CHILD = "jcr:child";
+ /**
+ * jcr:childNodeDefinition
+ */
+ public static final String JCR_CHILDNODEDEFINITION = "jcr:childNodeDefinition";
+ /**
+ * jcr:content
+ */
+ public static final String JCR_CONTENT = "jcr:content";
+ /**
+ * jcr:created
+ */
+ public static final String JCR_CREATED = "jcr:created";
+ /**
+ * jcr:data
+ */
+ public static final String JCR_DATA = "jcr:data";
+ /**
+ * jcr:defaultPrimaryType
+ */
+ public static final String JCR_DEFAULTPRIMARYTYPE = "jcr:defaultPrimaryType";
+ /**
+ * jcr:defaultValues
+ */
+ public static final String JCR_DEFAULTVALUES = "jcr:defaultValues";
+ /**
+ * jcr:encoding
+ */
+ public static final String JCR_ENCODING = "jcr:encoding";
+ /**
+ * jcr:frozenMixinTypes
+ */
+ public static final String JCR_FROZENMIXINTYPES = "jcr:frozenMixinTypes";
+ /**
+ * jcr:frozenNode
+ */
+ public static final String JCR_FROZENNODE = "jcr:frozenNode";
+ /**
+ * jcr:frozenPrimaryType
+ */
+ public static final String JCR_FROZENPRIMARYTYPE = "jcr:frozenPrimaryType";
+ /**
+ * jcr:frozenUuid
+ */
+ public static final String JCR_FROZENUUID = "jcr:frozenUuid";
+ /**
+ * jcr:hasOrderableChildNodes
+ */
+ public static final String JCR_HASORDERABLECHILDNODES = "jcr:hasOrderableChildNodes";
+ /**
+ * jcr:isCheckedOut
+ */
+ public static final String JCR_ISCHECKEDOUT = "jcr:isCheckedOut";
+ /**
+ * jcr:isMixin
+ */
+ public static final String JCR_ISMIXIN = "jcr:isMixin";
+ /**
+ * jcr:language
+ */
+ public static final String JCR_LANGUAGE = "jcr:language";
+ /**
+ * jcr:lastModified
+ */
+ public static final String JCR_LASTMODIFIED = "jcr:lastModified";
+ /**
+ * jcr:lockIsDeep
+ */
+ public static final String JCR_LOCKISDEEP = "jcr:lockIsDeep";
+ /**
+ * jcr:lockOwner
+ */
+ public static final String JCR_LOCKOWNER = "jcr:lockOwner";
+ /**
+ * jcr:mandatory
+ */
+ public static final String JCR_MANDATORY = "jcr:mandatory";
+ /**
+ * jcr:mergeFailed
+ */
+ public static final String JCR_MERGEFAILED = "jcr:mergeFailed";
+ /**
+ * jcr:mimeType
+ */
+ public static final String JCR_MIMETYPE = "jcr:mimeType";
+ /**
+ * jcr:mixinTypes
+ */
+ public static final String JCR_MIXINTYPES = "jcr:mixinTypes";
+ /**
+ * jcr:multiple
+ */
+ public static final String JCR_MULTIPLE = "jcr:multiple";
+ /**
+ * jcr:name
+ */
+ public static final String JCR_NAME = "jcr:name";
+ /**
+ * jcr:nodeTypeName
+ */
+ public static final String JCR_NODETYPENAME = "jcr:nodeTypeName";
+ /**
+ * jcr:onParentVersion
+ */
+ public static final String JCR_ONPARENTVERSION = "jcr:onParentVersion";
+ /**
+ * jcr:predecessors
+ */
+ public static final String JCR_PREDECESSORS = "jcr:predecessors";
+ /**
+ * jcr:primaryItemName
+ */
+ public static final String JCR_PRIMARYITEMNAME = "jcr:primaryItemName";
+ /**
+ * jcr:primaryType
+ */
+ public static final String JCR_PRIMARYTYPE = "jcr:primaryType";
+ /**
+ * jcr:propertyDefinition
+ */
+ public static final String JCR_PROPERTYDEFINITION = "jcr:propertyDefinition";
+ /**
+ * jcr:protected
+ */
+ public static final String JCR_PROTECTED = "jcr:protected";
+ /**
+ * jcr:requiredPrimaryTypes
+ */
+ public static final String JCR_REQUIREDPRIMARYTYPES = "jcr:requiredPrimaryTypes";
+ /**
+ * jcr:requiredType
+ */
+ public static final String JCR_REQUIREDTYPE = "jcr:requiredType";
+ /**
+ * jcr:rootVersion
+ */
+ public static final String JCR_ROOTVERSION = "jcr:rootVersion";
+ /**
+ * jcr:sameNameSiblings
+ */
+ public static final String JCR_SAMENAMESIBLINGS = "jcr:sameNameSiblings";
+ /**
+ * jcr:statement
+ */
+ public static final String JCR_STATEMENT = "jcr:statement";
+ /**
+ * jcr:successors
+ */
+ public static final String JCR_SUCCESSORS = "jcr:successors";
+ /**
+ * jcr:supertypes
+ */
+ public static final String JCR_SUPERTYPES = "jcr:supertypes";
+ /**
+ * jcr:system
+ */
+ public static final String JCR_SYSTEM = "jcr:system";
+ /**
+ * jcr:uuid
+ */
+ public static final String JCR_UUID = "jcr:uuid";
+ /**
+ * jcr:valueConstraints
+ */
+ public static final String JCR_VALUECONSTRAINTS = "jcr:valueConstraints";
+ /**
+ * jcr:versionHistory
+ */
+ public static final String JCR_VERSIONHISTORY = "jcr:versionHistory";
+ /**
+ * jcr:versionLabels
+ */
+ public static final String JCR_VERSIONLABELS = "jcr:versionLabels";
+ /**
+ * jcr:versionStorage
+ */
+ public static final String JCR_VERSIONSTORAGE = "jcr:versionStorage";
+ /**
+ * jcr:versionableUuid
+ */
+ public static final String JCR_VERSIONABLEUUID = "jcr:versionableUuid";
+
+ /**
+ * Pseudo property jcr:path used with query results
+ */
+ public static final String JCR_PATH = "jcr:path";
+ /**
+ * Pseudo property jcr:score used with query results
+ */
+ public static final String JCR_SCORE = "jcr:score";
+
+ /**
+ * mix:lockable
+ */
+ public static final String MIX_LOCKABLE = "mix:lockable";
+ /**
+ * mix:referenceable
+ */
+ public static final String MIX_REFERENCEABLE = "mix:referenceable";
+ /**
+ * mix:versionable
+ */
+ public static final String MIX_VERSIONABLE = "mix:versionable";
+ /**
+ * mix:shareable
+ */
+ public static final String MIX_SHAREABLE = "mix:shareable";
+ /**
+ * nt:base
+ */
+ public static final String NT_BASE = "nt:base";
+ /**
+ * nt:childNodeDefinition
+ */
+ public static final String NT_CHILDNODEDEFINITION = "nt:childNodeDefinition";
+ /**
+ * nt:file
+ */
+ public static final String NT_FILE = "nt:file";
+ /**
+ * nt:folder
+ */
+ public static final String NT_FOLDER = "nt:folder";
+ /**
+ * nt:frozenNode
+ */
+ public static final String NT_FROZENNODE = "nt:frozenNode";
+ /**
+ * nt:hierarchyNode
+ */
+ public static final String NT_HIERARCHYNODE = "nt:hierarchyNode";
+ /**
+ * nt:linkedFile
+ */
+ public static final String NT_LINKEDFILE = "nt:linkedFile";
+ /**
+ * nt:nodeType
+ */
+ public static final String NT_NODETYPE = "nt:nodeType";
+ /**
+ * nt:propertyDefinition
+ */
+ public static final String NT_PROPERTYDEFINITION = "nt:propertyDefinition";
+ /**
+ * nt:query
+ */
+ public static final String NT_QUERY = "nt:query";
+ /**
+ * nt:resource
+ */
+ public static final String NT_RESOURCE = "nt:resource";
+ /**
+ * nt:unstructured
+ */
+ public static final String NT_UNSTRUCTURED = "nt:unstructured";
+ /**
+ * nt:version
+ */
+ public static final String NT_VERSION = "nt:version";
+ /**
+ * nt:versionHistory
+ */
+ public static final String NT_VERSIONHISTORY = "nt:versionHistory";
+ /**
+ * nt:versionLabels
+ */
+ public static final String NT_VERSIONLABELS = "nt:versionLabels";
+ /**
+ * nt:versionedChild
+ */
+ public static final String NT_VERSIONEDCHILD = "nt:versionedChild";
+}
--- /dev/null
+package org.argeo.jcr;
+
+import java.beans.PropertyDescriptor;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+import org.argeo.ArgeoException;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+
+public class BeanNodeMapper implements NodeMapper {
+ // private final static Log log = LogFactory.getLog(BeanNodeMapper.class);
+
+ private final static String NODE_VALUE = "value";
+
+ // private String keyNode = "bean:key";
+ private String uuidProperty = "uuid";
+ private String classProperty = "class";
+
+ private Boolean versioning = false;
+ private Boolean strictUuidReference = false;
+
+ // TODO define a primaryNodeType Strategy
+ private String primaryNodeType = null;
+
+ private ClassLoader classLoader = getClass().getClassLoader();
+
+ private NodeMapperProvider nodeMapperProvider;
+
+ /**
+ * exposed method to retrieve a bean from a node
+ */
+ public Object load(Node node) {
+ try {
+ if (nodeMapperProvider != null) {
+ NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node);
+ if (nodeMapper != this) {
+ return nodeMapper.load(node);
+ }
+ }
+ return nodeToBean(node);
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot load object from node " + node, e);
+ }
+ }
+
+ /** Update an existing node with an object */
+ public void update(Node node, Object obj) {
+ try {
+ if (nodeMapperProvider != null) {
+
+ NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node);
+ if (nodeMapper != this) {
+ nodeMapper.update(node, obj);
+ } else
+ beanToNode(createBeanWrapper(obj), node);
+ } else
+ beanToNode(createBeanWrapper(obj), node);
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot update node " + node + " with "
+ + obj, e);
+ }
+ }
+
+ /**
+ * if no storage path is given; we use canonical path
+ *
+ * @see this.storagePath()
+ */
+ public Node save(Session session, Object obj) {
+ return save(session, storagePath(obj), obj);
+ }
+
+ /**
+ * Create a new node to store an object. If the parentNode doesn't exist, it
+ * is created
+ *
+ * the primaryNodeType may be initialized before
+ */
+ public Node save(Session session, String path, Object obj) {
+ try {
+ final Node node;
+ String parentPath = JcrUtils.parentPath(path);
+ // find or create parent node
+ Node parentNode;
+ if (session.itemExists(path))
+ parentNode = (Node) session.getItem(parentPath);
+ else {
+ parentNode = JcrUtils.mkdirs(session, parentPath, null,
+ versioning);
+ }
+ // create node
+
+ if (primaryNodeType != null)
+ node = parentNode.addNode(JcrUtils.lastPathElement(path),
+ primaryNodeType);
+ else
+ node = parentNode.addNode(JcrUtils.lastPathElement(path));
+
+ // Check specific cases
+ if (nodeMapperProvider != null) {
+ NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node);
+ if (nodeMapper != this) {
+ nodeMapper.update(node, obj);
+ return node;
+ }
+ }
+ update(node, obj);
+ return node;
+ } catch (ArgeoException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot save or update " + obj + " under "
+ + path, e);
+ }
+ }
+
+ /**
+ * Parse the FQN of a class to string with '/' delimiters Prefix the
+ * returned string with "/objects/"
+ */
+ public String storagePath(Object obj) {
+ String clss = obj.getClass().getName();
+ StringBuffer buf = new StringBuffer("/objects/");
+ StringTokenizer st = new StringTokenizer(clss, ".");
+ while (st.hasMoreTokens()) {
+ buf.append(st.nextToken()).append('/');
+ }
+ buf.append(obj.toString());
+ return buf.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ /**
+ * Transforms a node into an object of the class defined by classProperty Property
+ */
+ protected Object nodeToBean(Node node) throws RepositoryException {
+
+ try {
+ String clssName = node.getProperty(classProperty).getValue()
+ .getString();
+
+ BeanWrapper beanWrapper = createBeanWrapper(loadClass(clssName));
+
+ // process properties
+ PropertyIterator propIt = node.getProperties();
+ props: while (propIt.hasNext()) {
+ Property prop = propIt.nextProperty();
+ if (!beanWrapper.isWritableProperty(prop.getName()))
+ continue props;
+
+ PropertyDescriptor pd = beanWrapper.getPropertyDescriptor(prop
+ .getName());
+ Class propClass = pd.getPropertyType();
+
+ // Process case of List and its derived classes
+ // primitive list
+ if (propClass != null && List.class.isAssignableFrom(propClass)) {
+ List<Object> lst = new ArrayList<Object>();
+ Class<?> valuesClass = classFromProperty(prop);
+ if (valuesClass != null)
+ for (Value value : prop.getValues()) {
+ lst.add(asObject(value, valuesClass));
+ }
+ continue props;
+ }
+
+ // Case of other type of property accepted by jcr
+ // Long, Double, String, Binary, Date, Boolean, Name
+ Object value = asObject(prop.getValue(), pd.getPropertyType());
+ if (value != null)
+ beanWrapper.setPropertyValue(prop.getName(), value);
+ }
+
+ // process children nodes
+ NodeIterator nodeIt = node.getNodes();
+ nodes: while (nodeIt.hasNext()) {
+ Node childNode = nodeIt.nextNode();
+ String name = childNode.getName();
+ if (!beanWrapper.isWritableProperty(name))
+ continue nodes;
+
+ PropertyDescriptor pd = beanWrapper.getPropertyDescriptor(name);
+ Class propClass = pd.getPropertyType();
+
+ // objects list
+ if (propClass != null && List.class.isAssignableFrom(propClass)) {
+ String lstClass = childNode.getProperty(classProperty)
+ .getString();
+ List<Object> lst;
+ try {
+ lst = (List<Object>) loadClass(lstClass).newInstance();
+ } catch (Exception e) {
+ lst = new ArrayList<Object>();
+ }
+
+ NodeIterator valuesIt = childNode.getNodes();
+ while (valuesIt.hasNext()) {
+ Node lstValueNode = valuesIt.nextNode();
+ Object lstValue = nodeToBean(lstValueNode);
+ lst.add(lstValue);
+ }
+
+ beanWrapper.setPropertyValue(name, lst);
+ continue nodes;
+ }
+
+ // objects map
+ if (propClass != null && Map.class.isAssignableFrom(propClass)) {
+ String mapClass = childNode.getProperty(classProperty)
+ .getString();
+ Map<Object, Object> map;
+ try {
+ map = (Map<Object, Object>) loadClass(mapClass)
+ .newInstance();
+ } catch (Exception e) {
+ map = new HashMap<Object, Object>();
+ }
+
+ // properties
+ PropertyIterator keysPropIt = childNode.getProperties();
+ keyProps: while (keysPropIt.hasNext()) {
+ Property keyProp = keysPropIt.nextProperty();
+ // FIXME: use property editor
+ String key = keyProp.getName();
+ if (classProperty.equals(key))
+ continue keyProps;
+
+ Class keyPropClass = classFromProperty(keyProp);
+ if (keyPropClass != null) {
+ Object mapValue = asObject(keyProp.getValue(),
+ keyPropClass);
+ map.put(key, mapValue);
+ }
+ }
+
+ // node
+ NodeIterator keysIt = childNode.getNodes();
+ while (keysIt.hasNext()) {
+ Node mapValueNode = keysIt.nextNode();
+ // FIXME: use property editor
+ Object key = mapValueNode.getName();
+
+ Object mapValue = nodeToBean(mapValueNode);
+
+ map.put(key, mapValue);
+ }
+ beanWrapper.setPropertyValue(name, map);
+ continue nodes;
+ }
+
+ // default
+ Object value = nodeToBean(childNode);
+ beanWrapper.setPropertyValue(name, value);
+
+ }
+ return beanWrapper.getWrappedInstance();
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot map node " + node, e);
+ }
+ }
+
+ /**
+ * Transforms an object to the specified jcr Node in order to persist it.
+ *
+ * @param beanWrapper
+ * @param node
+ * @throws RepositoryException
+ */
+ protected void beanToNode(BeanWrapper beanWrapper, Node node)
+ throws RepositoryException {
+ properties: for (PropertyDescriptor pd : beanWrapper
+ .getPropertyDescriptors()) {
+ String name = pd.getName();
+ if (!beanWrapper.isReadableProperty(name))
+ continue properties;// skip
+
+ Object value = beanWrapper.getPropertyValue(name);
+ if (value == null) {
+ // remove values when updating
+ if (node.hasProperty(name))
+ node.setProperty(name, (Value) null);
+ if (node.hasNode(name))
+ node.getNode(name).remove();
+
+ continue properties;
+ }
+
+ // if (uuidProperty != null && uuidProperty.equals(name)) {
+ // // node.addMixin(ArgeoJcrConstants.MIX_REFERENCEABLE);
+ // node.setProperty(ArgeoJcrConstants.JCR_UUID, value.toString());
+ // continue properties;
+ // }
+
+ if ("class".equals(name)) {
+ if (classProperty != null) {
+ node.setProperty(classProperty, ((Class<?>) value)
+ .getName());
+ // TODO: store a class hierarchy?
+ }
+ continue properties;
+ }
+
+ // Some bean reference other classes. We must deal with this case
+ if (value instanceof Class<?>) {
+ node.setProperty(name, ((Class<?>) value).getName());
+ continue properties;
+ }
+
+ Value val = asValue(node.getSession(), value);
+ if (val != null) {
+ node.setProperty(name, val);
+ continue properties;
+ }
+
+ if (value instanceof List<?>) {
+ List<?> lst = (List<?>) value;
+ addList(node, name, lst);
+ continue properties;
+ }
+
+ if (value instanceof Map<?, ?>) {
+ Map<?, ?> map = (Map<?, ?>) value;
+ addMap(node, name, map);
+ continue properties;
+ }
+
+ BeanWrapper child = createBeanWrapper(value);
+ // TODO: delegate to another mapper
+
+ // TODO: deal with references
+ // Node childNode = findChildReference(session, child);
+ // if (childNode != null) {
+ // node.setProperty(name, childNode);
+ // continue properties;
+ // }
+
+ // default case (recursive)
+ if (node.hasNode(name)) {// update
+ // TODO: optimize
+ node.getNode(name).remove();
+ }
+ Node childNode = node.addNode(name);
+ beanToNode(child, childNode);
+ }
+ }
+
+ /**
+ * Process specific case of list
+ *
+ * @param node
+ * @param name
+ * @param lst
+ * @throws RepositoryException
+ */
+ protected void addList(Node node, String name, List<?> lst)
+ throws RepositoryException {
+ if (node.hasNode(name)) {// update
+ // TODO: optimize
+ node.getNode(name).remove();
+ }
+
+ Node listNode = node.addNode(name);
+ listNode.setProperty(classProperty, lst.getClass().getName());
+ Value[] values = new Value[lst.size()];
+ boolean atLeastOneSet = false;
+ for (int i = 0; i < lst.size(); i++) {
+ Object lstValue = lst.get(i);
+ values[i] = asValue(node.getSession(), lstValue);
+ if (values[i] != null) {
+ atLeastOneSet = true;
+ } else {
+ Node childNode = findChildReference(node.getSession(),
+ createBeanWrapper(lstValue));
+ if (childNode != null) {
+ values[i] = node.getSession().getValueFactory()
+ .createValue(childNode);
+ atLeastOneSet = true;
+ }
+ }
+ }
+
+ // will be either properties or nodes, not both
+ if (!atLeastOneSet && lst.size() != 0) {
+ for (Object lstValue : lst) {
+ Node childNode = listNode.addNode(NODE_VALUE);
+ beanToNode(createBeanWrapper(lstValue), childNode);
+ }
+ } else {
+ listNode.setProperty(name, values);
+ }
+ }
+
+ /**
+ * Process specific case of maps.
+ *
+ * @param node
+ * @param name
+ * @param map
+ * @throws RepositoryException
+ */
+ protected void addMap(Node node, String name, Map<?, ?> map)
+ throws RepositoryException {
+ if (node.hasNode(name)) {// update
+ // TODO: optimize
+ node.getNode(name).remove();
+ }
+
+ Node mapNode = node.addNode(name);
+ mapNode.setProperty(classProperty, map.getClass().getName());
+ for (Object key : map.keySet()) {
+ Object mapValue = map.get(key);
+ // PropertyEditor pe = beanWrapper.findCustomEditor(key.getClass(),
+ // null);
+ String keyStr;
+ // if (pe == null) {
+ if (key instanceof CharSequence)
+ keyStr = key.toString();
+ else
+ throw new ArgeoException(
+ "Cannot find property editor for class "
+ + key.getClass());
+ // } else {
+ // pe.setValue(key);
+ // keyStr = pe.getAsText();
+ // }
+ // TODO: check string format
+
+ Value mapVal = asValue(node.getSession(), mapValue);
+ if (mapVal != null)
+ mapNode.setProperty(keyStr, mapVal);
+ else {
+ Node entryNode = mapNode.addNode(keyStr);
+ beanToNode(createBeanWrapper(mapValue), entryNode);
+ }
+
+ }
+
+ }
+
+ protected BeanWrapper createBeanWrapper(Object obj) {
+ return new BeanWrapperImpl(obj);
+ }
+
+ protected BeanWrapper createBeanWrapper(Class<?> clss) {
+ return new BeanWrapperImpl(clss);
+ }
+
+ /** Returns null if value cannot be found */
+ protected Value asValue(Session session, Object value)
+ throws RepositoryException {
+ ValueFactory valueFactory = session.getValueFactory();
+ if (value instanceof Integer)
+ return valueFactory.createValue((Integer) value);
+ else if (value instanceof Long)
+ return valueFactory.createValue((Long) value);
+ else if (value instanceof Float)
+ return valueFactory.createValue((Float) value);
+ else if (value instanceof Double)
+ return valueFactory.createValue((Double) value);
+ else if (value instanceof Boolean)
+ return valueFactory.createValue((Boolean) value);
+ else if (value instanceof Calendar)
+ return valueFactory.createValue((Calendar) value);
+ else if (value instanceof Date) {
+ Calendar cal = new GregorianCalendar();
+ cal.setTime((Date) value);
+ return valueFactory.createValue(cal);
+ } else if (value instanceof CharSequence)
+ return valueFactory.createValue(value.toString());
+ else if (value instanceof InputStream)
+ return valueFactory.createValue((InputStream) value);
+ else
+ return null;
+ }
+
+ protected Class<?> classFromProperty(Property property)
+ throws RepositoryException {
+ switch (property.getType()) {
+ case PropertyType.LONG:
+ return Long.class;
+ case PropertyType.DOUBLE:
+ return Double.class;
+ case PropertyType.STRING:
+ return String.class;
+ case PropertyType.BOOLEAN:
+ return Boolean.class;
+ case PropertyType.DATE:
+ return Calendar.class;
+ case PropertyType.NAME:
+ return null;
+ default:
+ throw new ArgeoException("Cannot find class for property "
+ + property + ", type="
+ + PropertyType.nameFromValue(property.getType()));
+ }
+ }
+
+ protected Object asObject(Value value, Class<?> propClass)
+ throws RepositoryException {
+ if (propClass.equals(Integer.class))
+ return (int) value.getLong();
+ else if (propClass.equals(Long.class))
+ return value.getLong();
+ else if (propClass.equals(Float.class))
+ return (float) value.getDouble();
+ else if (propClass.equals(Double.class))
+ return value.getDouble();
+ else if (propClass.equals(Boolean.class))
+ return value.getBoolean();
+ else if (CharSequence.class.isAssignableFrom(propClass))
+ return value.getString();
+ else if (InputStream.class.isAssignableFrom(propClass))
+ return value.getStream();
+ else if (Calendar.class.isAssignableFrom(propClass))
+ return value.getDate();
+ else if (Date.class.isAssignableFrom(propClass))
+ return value.getDate().getTime();
+ else
+ return null;
+ }
+
+ protected Node findChildReference(Session session, BeanWrapper child)
+ throws RepositoryException {
+ if (child.isReadableProperty(uuidProperty)) {
+ String childUuid = child.getPropertyValue(uuidProperty).toString();
+ try {
+ return session.getNodeByUUID(childUuid);
+ } catch (ItemNotFoundException e) {
+ if (strictUuidReference)
+ throw new ArgeoException("No node found with uuid "
+ + childUuid, e);
+ }
+ }
+ return null;
+ }
+
+ protected Class<?> loadClass(String name) {
+ // log.debug("Class loader: " + classLoader);
+ try {
+ return classLoader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ throw new ArgeoException("Cannot load class " + name, e);
+ }
+ }
+
+ protected String propertyName(String name) {
+ return name;
+ }
+
+ public void setVersioning(Boolean versioning) {
+ this.versioning = versioning;
+ }
+
+ public void setUuidProperty(String uuidProperty) {
+ this.uuidProperty = uuidProperty;
+ }
+
+ public void setClassProperty(String classProperty) {
+ this.classProperty = classProperty;
+ }
+
+ public void setStrictUuidReference(Boolean strictUuidReference) {
+ this.strictUuidReference = strictUuidReference;
+ }
+
+ public void setPrimaryNodeType(String primaryNodeType) {
+ this.primaryNodeType = primaryNodeType;
+ }
+
+ public void setClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ public void setNodeMapperProvider(NodeMapperProvider nodeMapperProvider) {
+ this.nodeMapperProvider = nodeMapperProvider;
+ }
+
+ public String getPrimaryNodeType() {
+ return this.primaryNodeType;
+ }
+
+ public String getClassProperty() {
+ return this.classProperty;
+ }
+}
--- /dev/null
+package org.argeo.jcr;
+
+import java.util.Calendar;
+import java.util.StringTokenizer;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+
+public class JcrUtils {
+ private final static Log log = LogFactory.getLog(JcrUtils.class);
+
+ public static Node querySingleNode(Query query) {
+ NodeIterator nodeIterator;
+ try {
+ QueryResult queryResult = query.execute();
+ nodeIterator = queryResult.getNodes();
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot execute query " + query, e);
+ }
+ Node node;
+ if (nodeIterator.hasNext())
+ node = nodeIterator.nextNode();
+ else
+ return null;
+
+ if (nodeIterator.hasNext())
+ throw new ArgeoException("Query returned more than one node.");
+ return node;
+ }
+
+ public static String removeForbiddenCharacters(String str) {
+ return str.replace('[', '_').replace(']', '_').replace('/', '_')
+ .replace('*', '_');
+
+ }
+
+ public static String parentPath(String path) {
+ if (path.equals("/"))
+ throw new ArgeoException("Root path '/' has no parent path");
+ if (path.charAt(0) != '/')
+ throw new ArgeoException("Path " + path + " must start with a '/'");
+ String pathT = path;
+ if (pathT.charAt(pathT.length() - 1) == '/')
+ pathT = pathT.substring(0, pathT.length() - 2);
+
+ int index = pathT.lastIndexOf('/');
+ return pathT.substring(0, index);
+ }
+
+ public static String dateAsPath(Calendar cal) {
+ StringBuffer buf = new StringBuffer(14);
+ buf.append('Y').append(cal.get(Calendar.YEAR));// 5
+ buf.append('/');// 1
+ int month = cal.get(Calendar.MONTH) + 1;
+ buf.append('M');
+ if (month < 10)
+ buf.append(0);
+ buf.append(month);// 3
+ buf.append('/');// 1
+ int day = cal.get(Calendar.DAY_OF_MONTH);
+ if (day < 10)
+ buf.append(0);
+ buf.append('D').append(day);// 3
+ buf.append('/');// 1
+ return buf.toString();
+
+ }
+
+ public static String hostAsPath(String host) {
+ // TODO : inverse order of the elements (to have org/argeo/test IO
+ // test/argeo/org
+ return host.replace('.', '/');
+ }
+
+ public static String lastPathElement(String path) {
+ if (path.charAt(path.length() - 1) == '/')
+ throw new ArgeoException("Path " + path + " cannot end with '/'");
+ int index = path.lastIndexOf('/');
+ if (index < 0)
+ throw new ArgeoException("Cannot find last path element for "
+ + path);
+ return path.substring(index + 1);
+ }
+
+ public static Node mkdirs(Session session, String path) {
+ return mkdirs(session, path, null, false);
+ }
+
+ public static Node mkdirs(Session session, String path, String type,
+ Boolean versioning) {
+ try {
+ if (path.equals('/'))
+ return session.getRootNode();
+
+ StringTokenizer st = new StringTokenizer(path, "/");
+ StringBuffer current = new StringBuffer("/");
+ Node currentNode = session.getRootNode();
+ while (st.hasMoreTokens()) {
+ String part = st.nextToken();
+ current.append(part).append('/');
+ if (!session.itemExists(current.toString())) {
+ if (type != null)
+ currentNode = currentNode.addNode(part, type);
+ else
+ currentNode = currentNode.addNode(part);
+ if (versioning)
+ currentNode.addMixin(ArgeoJcrConstants.MIX_VERSIONABLE);
+ if (log.isTraceEnabled())
+ log.debug("Added folder " + part + " as " + current);
+ } else {
+ currentNode = (Node) session.getItem(current.toString());
+ }
+ }
+ session.save();
+ return currentNode;
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot mkdirs " + path, e);
+ }
+ }
+
+ public static void registerNamespaceSafely(Session session, String prefix,
+ String uri) {
+ try {
+ registerNamespaceSafely(session.getWorkspace()
+ .getNamespaceRegistry(), prefix, uri);
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot find namespace registry", e);
+ }
+ }
+
+ public static void registerNamespaceSafely(NamespaceRegistry nr,
+ String prefix, String uri) {
+ try {
+ String[] prefixes = nr.getPrefixes();
+ for (String pref : prefixes)
+ if (pref.equals(prefix)) {
+ String registeredUri = nr.getURI(pref);
+ if (!registeredUri.equals(uri))
+ throw new ArgeoException("Prefix " + pref
+ + " already registered for URI "
+ + registeredUri
+ + " which is different from provided URI "
+ + uri);
+ else
+ return;// skip
+ }
+ nr.registerNamespace(prefix, uri);
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot register namespace " + uri
+ + " under prefix " + prefix, e);
+ }
+ }
+
+ /** Recursively outputs the contents of the given node. */
+ public static void debug(Node node) throws RepositoryException {
+ // First output the node path
+ log.debug(node.getPath());
+ // Skip the virtual (and large!) jcr:system subtree
+ if (node.getName().equals(ArgeoJcrConstants.JCR_SYSTEM)) {
+ return;
+ }
+
+ // Then the children nodes (recursive)
+ NodeIterator it = node.getNodes();
+ while (it.hasNext()) {
+ Node childNode = it.nextNode();
+ debug(childNode);
+ }
+
+ // Then output the properties
+ PropertyIterator properties = node.getProperties();
+ // log.debug("Property are : ");
+
+ while (properties.hasNext()) {
+ Property property = properties.nextProperty();
+ if (property.getDefinition().isMultiple()) {
+ // A multi-valued property, print all values
+ Value[] values = property.getValues();
+ for (int i = 0; i < values.length; i++) {
+ log.debug(property.getPath() + "=" + values[i].getString());
+ }
+ } else {
+ // A single-valued property
+ log.debug(property.getPath() + "=" + property.getString());
+ }
+ }
+
+ }
+}
--- /dev/null
+package org.argeo.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+public interface NodeMapper {
+ public Object load(Node node);
+
+ public void update(Node node, Object obj);
+
+ public Node save(Session session, String path, Object obj);
+
+ public void setNodeMapperProvider(NodeMapperProvider nmp);
+}
--- /dev/null
+package org.argeo.jcr;
+
+import javax.jcr.Node;
+
+/** Provides a node mapper relevant for this node. */
+public interface NodeMapperProvider {
+
+ /**
+ * Node Mapper is chosen regarding the Jcr path of the node parameter
+ * @param Node node
+ * @return the node mapper or null if no relevant node mapper can be found. */
+ public NodeMapper findNodeMapper(Node node);
+}
--- /dev/null
+package org.argeo.jcr;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+
+public class ThreadBoundJcrSessionFactory implements FactoryBean,
+ DisposableBean {
+ private final static Log log = LogFactory
+ .getLog(ThreadBoundJcrSessionFactory.class);
+
+ private Repository repository;
+ private List<Session> activeSessions = Collections
+ .synchronizedList(new ArrayList<Session>());
+
+ private ThreadLocal<Session> session = new ThreadLocal<Session>();
+ private boolean destroying = false;
+ private final Session proxiedSession;
+
+ public ThreadBoundJcrSessionFactory() {
+ Class<?>[] interfaces = { Session.class };
+ proxiedSession = (Session) Proxy.newProxyInstance(getClass()
+ .getClassLoader(), interfaces, new InvocationHandler() {
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ Session threadSession = session.get();
+ if (threadSession == null) {
+ if ("logout".equals(method.getName()))// no need to login
+ return Void.TYPE;
+ threadSession = login();
+ session.set(threadSession);
+ }
+
+ Object ret = method.invoke(threadSession, args);
+ if ("logout".equals(method.getName())) {
+ session.remove();
+ if (!destroying)
+ activeSessions.remove(threadSession);
+ if (log.isTraceEnabled())
+ log.trace("Logged out from JCR session "
+ + threadSession + "; userId="
+ + threadSession.getUserID());
+ }
+ return ret;
+ }
+ });
+ }
+
+ protected Session login() {
+ try {
+ Session sess = repository.login();
+ if (log.isTraceEnabled())
+ log.trace("Log in to JCR session " + sess + "; userId="
+ + sess.getUserID());
+ // Thread.dumpStack();
+ activeSessions.add(sess);
+ return sess;
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot log in to repository", e);
+ }
+ }
+
+ public Object getObject() {
+ return proxiedSession;
+ }
+
+ public void destroy() throws Exception {
+ if (log.isDebugEnabled())
+ log.debug("Cleaning up " + activeSessions.size()
+ + " active JCR sessions...");
+
+ destroying = true;
+ for (Session sess : activeSessions) {
+ sess.logout();
+ }
+ activeSessions.clear();
+ }
+
+ public Class<? extends Session> getObjectType() {
+ return Session.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+}
--- /dev/null
+package org.argeo.server.jcr;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+
+/** To be overridden */
+public class DefaultJcrListener implements EventListener {
+ private final static Log log = LogFactory.getLog(DefaultJcrListener.class);
+ private Session session;
+ private Repository repository;
+ private String path = "/";
+ private Boolean deep = true;
+ private String username = "demo";
+ private String password = "demo";
+
+ public void start() {
+ try {
+ addEventListener(session().getWorkspace().getObservationManager());
+ if (log.isDebugEnabled())
+ log.debug("Registered JCR event listener on " + path);
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot register event listener", e);
+ }
+ }
+
+ public void stop() {
+ try {
+ session().getWorkspace().getObservationManager()
+ .removeEventListener(this);
+ if (log.isDebugEnabled())
+ log.debug("Unregistered JCR event listener on " + path);
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot unregister event listener", e);
+ }
+ }
+
+ /** Default is listen to all events */
+ protected Integer getEvents() {
+ return Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED
+ | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
+ }
+
+ /** To be overidden */
+ public void onEvent(EventIterator events) {
+ while (events.hasNext()) {
+ Event event = events.nextEvent();
+ log.debug(event);
+ }
+ }
+
+ /** To be overidden */
+ protected void addEventListener(ObservationManager observationManager)
+ throws RepositoryException {
+ observationManager.addEventListener(this, getEvents(), path, deep,
+ null, null, false);
+ }
+
+ protected Session session() {
+ if (session == null)
+ try {
+ session = repository.login(new SimpleCredentials(username,
+ password.toCharArray()));
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot open session", e);
+ }
+ return session;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public void setDeep(Boolean deep) {
+ this.deep = deep;
+ }
+
+}
--- /dev/null
+package org.argeo.server.jcr;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import javax.activation.MimetypesFileTypeMap;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionIterator;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.Resource;
+
+public class JcrResourceAdapter implements InitializingBean, DisposableBean {
+ private final static Log log = LogFactory.getLog(JcrResourceAdapter.class);
+
+ private Repository repository;
+
+ private String username;
+ private String password;
+
+ private Session session;
+
+ private Boolean versioning = true;
+ private String defaultEncoding = "UTF-8";
+
+ // private String restoreBase = "/.restore";
+
+ public void mkdirs(String path) {
+ JcrUtils.mkdirs(session(), path, "nt:folder", versioning);
+ }
+
+ public void create(String path, Resource file, String mimeType) {
+ try {
+ create(path, file.getInputStream(), mimeType);
+ } catch (IOException e) {
+ throw new ArgeoException("Cannot read " + file, e);
+ }
+ }
+
+ public void create(String path, InputStream in, String mimeType) {
+ try {
+ if (session().itemExists(path)) {
+ throw new ArgeoException("Node " + path + " already exists.");
+ }
+
+ int index = path.lastIndexOf('/');
+ String parentPath = path.substring(0, index);
+ if (parentPath.equals(""))
+ parentPath = "/";
+ String fileName = path.substring(index + 1);
+ if (!session().itemExists(parentPath))
+ throw new ArgeoException("Parent folder of node " + path
+ + " does not exist: " + parentPath);
+
+ Node folderNode = (Node) session().getItem(parentPath);
+ Node fileNode = folderNode.addNode(fileName, "nt:file");
+
+ Node contentNode = fileNode.addNode("jcr:content", "nt:resource");
+ if (mimeType != null)
+ contentNode.setProperty("jcr:mimeType", mimeType);
+ contentNode.setProperty("jcr:encoding", defaultEncoding);
+ contentNode.setProperty("jcr:data", in);
+ Calendar lastModified = Calendar.getInstance();
+ // lastModified.setTimeInMillis(file.lastModified());
+ contentNode.setProperty("jcr:lastModified", lastModified);
+ // resNode.addMixin("mix:referenceable");
+
+ if (versioning)
+ fileNode.addMixin("mix:versionable");
+
+ session().save();
+
+ if (versioning)
+ fileNode.checkin();
+
+ if (log.isDebugEnabled())
+ log.debug("Created " + path);
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot create node for " + path, e);
+ }
+
+ }
+
+ public void update(String path, Resource file) {
+ try {
+ update(path, file.getInputStream());
+ } catch (IOException e) {
+ throw new ArgeoException("Cannot read " + file, e);
+ }
+ }
+
+ public void update(String path, InputStream in) {
+ try {
+
+ if (!session().itemExists(path)) {
+ String type = new MimetypesFileTypeMap()
+ .getContentType(FilenameUtils.getName(path));
+ create(path, in, type);
+ return;
+ }
+
+ Node fileNode = (Node) session().getItem(path);
+ Node contentNode = fileNode.getNode("jcr:content");
+ fileNode.checkout();
+ contentNode.setProperty("jcr:data", in);
+ Calendar lastModified = Calendar.getInstance();
+ // lastModified.setTimeInMillis(file.lastModified());
+ contentNode.setProperty("jcr:lastModified", lastModified);
+
+ session().save();
+ fileNode.checkin();
+
+ if (log.isDebugEnabled())
+ log.debug("Updated " + path);
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot update node " + path, e);
+ }
+ }
+
+ public List<Calendar> listVersions(String path) {
+ if (!versioning)
+ throw new ArgeoException("Versioning is not activated");
+
+ try {
+ List<Calendar> versions = new ArrayList<Calendar>();
+ Node fileNode = (Node) session().getItem(path);
+ VersionHistory history = fileNode.getVersionHistory();
+ for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
+ Version version = (Version) it.next();
+ versions.add(version.getCreated());
+ if (log.isTraceEnabled()) {
+ log.debug(version);
+ // debug(version);
+ }
+ }
+ return versions;
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot list version of node " + path, e);
+ }
+ }
+
+ public InputStream retrieve(String path) {
+ try {
+ Node node = (Node) session().getItem(path + "/jcr:content");
+ Property property = node.getProperty("jcr:data");
+ return property.getStream();
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot retrieve " + path, e);
+ }
+ }
+
+ public synchronized InputStream retrieve(String path, Integer revision) {
+ if (!versioning)
+ throw new ArgeoException("Versioning is not activated");
+
+ try {
+ Node fileNode = (Node) session().getItem(path);
+ VersionHistory history = fileNode.getVersionHistory();
+ int count = 0;
+ Version version = null;
+ for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
+ version = (Version) it.next();
+ if (count == revision + 1) {
+ InputStream in = fromVersion(version);
+ if (log.isDebugEnabled())
+ log.debug("Retrieved " + path + " at revision "
+ + revision);
+ return in;
+ }
+ count++;
+ }
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot retrieve version " + revision
+ + " of " + path, e);
+ }
+
+ throw new ArgeoException("Version " + revision
+ + " does not exist for node " + path);
+ }
+
+ protected InputStream fromVersion(Version version)
+ throws RepositoryException {
+ Node frozenNode = version.getNode("jcr:frozenNode");
+ InputStream in = frozenNode.getNode("jcr:content").getProperty(
+ "jcr:data").getStream();
+ return in;
+ }
+
+ protected Session session() {
+ return session;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ session = repository.login(new SimpleCredentials(username, password
+ .toCharArray()));
+ }
+
+ public void destroy() throws Exception {
+ session.logout();
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void setVersioning(Boolean versioning) {
+ this.versioning = versioning;
+ }
+
+ public void setDefaultEncoding(String defaultEncoding) {
+ this.defaultEncoding = defaultEncoding;
+ }
+
+ protected String fill(Integer number) {
+ int size = 4;
+ String str = number.toString();
+ for (int i = str.length(); i < size; i++) {
+ str = "0" + str;
+ }
+ return str;
+ }
+}
--- /dev/null
+package org.argeo.server.jcr.mvc;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Item;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+import javax.jcr.query.RowIterator;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.WebRequest;
+
+@Controller
+public class JcrBrowserController implements JcrMvcConstants {
+
+ @RequestMapping("/getJcrItem.*")
+ public Item getJcrItem(WebRequest webRequest,
+ @RequestParam("path") String path) throws RepositoryException {
+ return ((Session) webRequest.getAttribute(REQUEST_ATTR_SESSION,
+ RequestAttributes.SCOPE_REQUEST)).getItem(path);
+ }
+
+ @RequestMapping("/queryJcrNodes.*")
+ public List<String> queryJcrNodes(WebRequest webRequest,
+ @RequestParam("statement") String statement,
+ @RequestParam("language") String language)
+ throws RepositoryException {
+ Session session = ((Session) webRequest.getAttribute(
+ REQUEST_ATTR_SESSION, RequestAttributes.SCOPE_REQUEST));
+ Query query = session.getWorkspace().getQueryManager().createQuery(
+ statement, language);
+ NodeIterator nit = query.execute().getNodes();
+ List<String> paths = new ArrayList<String>();
+ while (nit.hasNext()) {
+ paths.add(nit.nextNode().getPath());
+ }
+ return paths;
+ }
+
+ @RequestMapping("/queryJcrTable.*")
+ public List<List<String>> queryJcrTable(WebRequest webRequest,
+ @RequestParam("statement") String statement,
+ @RequestParam("language") String language)
+ throws RepositoryException {
+ Session session = ((Session) webRequest.getAttribute(
+ REQUEST_ATTR_SESSION, RequestAttributes.SCOPE_REQUEST));
+ Query query = session.getWorkspace().getQueryManager().createQuery(
+ statement, language);
+ QueryResult queryResult = query.execute();
+ List<List<String>> results = new ArrayList<List<String>>();
+ results.add(Arrays.asList(queryResult.getColumnNames()));
+ RowIterator rit = queryResult.getRows();
+
+ while (rit.hasNext()) {
+ Row row = rit.nextRow();
+ List<String> lst = new ArrayList<String>();
+ for (Value value : row.getValues()) {
+ lst.add(value.getString());
+ }
+ }
+ return results;
+ }
+}
--- /dev/null
+package org.argeo.server.jcr.mvc;
+
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileItemFactory;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.server.ServerAnswer;
+import org.argeo.server.jcr.JcrResourceAdapter;
+import org.argeo.server.mvc.MvcConstants;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+public class JcrManagerController implements MvcConstants {
+ private final static Log log = LogFactory
+ .getLog(JcrManagerController.class);
+
+ private JcrResourceAdapter resourceAdapter;
+
+ // Create a factory for disk-based file items
+ private FileItemFactory factory = new DiskFileItemFactory();
+
+ // Create a new file upload handler
+ private ServletFileUpload upload = new ServletFileUpload(factory);
+
+ @SuppressWarnings("unchecked")
+ @RequestMapping("/upload/**")
+ @ModelAttribute(ANSWER_MODEL_KEY_AS_HTML)
+ public ServerAnswer upload(HttpServletRequest request,
+ HttpServletResponse response) throws Exception {
+ // Parse the request
+ List<FileItem> items = upload.parseRequest(request);
+
+ byte[] arr = null;
+ for (FileItem item : items) {
+ if (!item.isFormField()) {
+ arr = item.get();
+ break;
+ }
+ }
+
+ ByteArrayResource res = new ByteArrayResource(arr);
+ // String pathInfo = request.getPathInfo();
+
+ StringBuffer path = new StringBuffer("/");
+ StringTokenizer st = new StringTokenizer(request.getPathInfo(), "/");
+ st.nextToken();// skip /upload/
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+ if (!st.hasMoreTokens()) {
+ resourceAdapter.mkdirs(path.toString());
+ path.append(token);
+ } else {
+ path.append(token).append('/');
+ }
+ }
+ // String path = '/' + pathInfo.substring(1).substring(
+ // pathInfo.indexOf('/'));
+ if (log.isDebugEnabled())
+ log.debug("Upload to " + path);
+ resourceAdapter.update(path.toString(), res);
+ return ServerAnswer.ok("File " + path + " imported");
+ }
+
+ public void setResourceAdapter(JcrResourceAdapter resourceAdapter) {
+ this.resourceAdapter = resourceAdapter;
+ }
+
+}
--- /dev/null
+package org.argeo.server.jcr.mvc;
+
+public interface JcrMvcConstants {
+ public final static String REQUEST_ATTR_SESSION = "jcrSession";
+}
--- /dev/null
+package org.argeo.server.jcr.mvc;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.argeo.ArgeoException;
+import org.argeo.server.ServerSerializer;
+import org.springframework.xml.dom.DomContentHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+public class JcrXmlServerSerializer implements ServerSerializer {
+ private String contentTypeCharset = "UTF-8";
+
+ private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
+ .newInstance();
+ private final TransformerFactory transformerFactory = TransformerFactory
+ .newInstance();
+
+ public void serialize(Object obj, HttpServletRequest request,
+ HttpServletResponse response) {
+ if (!(obj instanceof Node))
+ throw new ArgeoException("Only " + Node.class + " is supported");
+
+ String noRecurseStr = request.getParameter("noRecurse");
+ boolean noRecurse = noRecurseStr != null && noRecurseStr.equals("true");
+
+ String depthStr = request.getParameter("depth");
+ String downloadStr = request.getParameter("download");
+
+ Node node = (Node) obj;
+
+ try {
+ String contentType = "text/xml;charset=" + contentTypeCharset;
+ // download case
+ if (downloadStr != null && downloadStr.equals("true")) {
+ String fileName = node.getName().replace(':', '_') + ".xml";
+ contentType = contentType + ";name=\"" + fileName + "\"";
+ response.setHeader("Content-Disposition",
+ "attachment; filename=\"" + fileName + "\"");
+ response.setHeader("Expires", "0");
+ response
+ .setHeader("Cache-Control", "no-cache, must-revalidate");
+ response.setHeader("Pragma", "no-cache");
+ }
+
+ response.setContentType(contentType);
+ if (depthStr == null) {
+ node.getSession().exportDocumentView(node.getPath(),
+ response.getOutputStream(), true, noRecurse);
+ } else {
+ int depth = Integer.parseInt(depthStr);
+ Document document = documentBuilderFactory.newDocumentBuilder()
+ .newDocument();
+ serializeLevelToDom(node, document, 0, depth);
+ Transformer transformer = transformerFactory.newTransformer();
+ transformer.transform(new DOMSource(document),
+ new StreamResult(response.getOutputStream()));
+ }
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot serialize " + node, e);
+ }
+ }
+
+ protected void serializeLevelToDom(Node currentJcrNode,
+ org.w3c.dom.Node currentDomNode, int currentDepth, int targetDepth)
+ throws RepositoryException, SAXException {
+ DomContentHandler domContentHandler = new DomContentHandler(
+ currentDomNode);
+ currentJcrNode.getSession().exportDocumentView(
+ currentJcrNode.getPath(), domContentHandler, true, true);
+
+ if (currentDepth == targetDepth)
+ return;
+
+ // TODO: filter
+ NodeIterator nit = currentJcrNode.getNodes();
+ while (nit.hasNext()) {
+ Node nextJcrNode = nit.nextNode();
+ org.w3c.dom.Node nextDomNode;
+ if (currentDomNode instanceof Document)
+ nextDomNode = ((Document) currentDomNode).getDocumentElement();
+ else {
+ String name = currentJcrNode.getName();
+ NodeList nodeList = ((Element) currentDomNode)
+ .getElementsByTagName(name);
+ if (nodeList.getLength() < 1)
+ throw new ArgeoException("No elment named " + name
+ + " under " + currentDomNode);
+ // we know it is the last one added
+ nextDomNode = nodeList.item(nodeList.getLength() - 1);
+ }
+ // recursive call
+ serializeLevelToDom(nextJcrNode, nextDomNode, currentDepth + 1,
+ targetDepth);
+ }
+ }
+
+ public void setContentTypeCharset(String contentTypeCharset) {
+ this.contentTypeCharset = contentTypeCharset;
+ }
+
+}
--- /dev/null
+package org.argeo.server.jcr.mvc;
+
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.WebRequestInterceptor;
+
+public class OpenSessionInViewJcrInterceptor implements WebRequestInterceptor,
+ JcrMvcConstants {
+ private final static Log log = LogFactory
+ .getLog(OpenSessionInViewJcrInterceptor.class);
+
+ private Session session;
+
+ public void preHandle(WebRequest request) throws Exception {
+ if (log.isTraceEnabled())
+ log.trace("preHandle: " + request);
+ // Authentication auth = SecurityContextHolder.getContext()
+ // .getAuthentication();
+ // if (auth != null)
+ // log.debug("auth=" + auth + ", authenticated="
+ // + auth.isAuthenticated() + ", name=" + auth.getName());
+ // else
+ // log.debug("No auth");
+
+ // FIXME: find a safer way to initialize
+ // FIXME: not really needed to initialize here
+ // session.getRepository();
+ request.setAttribute(REQUEST_ATTR_SESSION, session,
+ RequestAttributes.SCOPE_REQUEST);
+ }
+
+ public void postHandle(WebRequest request, ModelMap model) throws Exception {
+ // if (log.isDebugEnabled())
+ // log.debug("postHandle: " + request);
+ }
+
+ public void afterCompletion(WebRequest request, Exception ex)
+ throws Exception {
+ if (log.isTraceEnabled())
+ log.trace("afterCompletion: " + request);
+ // FIXME: only close session that were open
+ session.logout();
+ }
+
+ public void setSession(Session session) {
+ this.session = session;
+ }
+
+}
--- /dev/null
+package org.argeo.jcr;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CollectionsObject {
+ private String id;
+ private String label;
+ private SimpleObject simpleObject;
+ private List<String> stringList = new ArrayList<String>();
+ private Map<String, Float> floatMap = new HashMap<String, Float>();
+ private Map<SimpleObject, String> objectMap = new HashMap<SimpleObject, String>();
+ private Map<String, Map<String, String>> mapOfMaps = new HashMap<String, Map<String, String>>();
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public SimpleObject getSimpleObject() {
+ return simpleObject;
+ }
+
+ public void setSimpleObject(SimpleObject simpleObject) {
+ this.simpleObject = simpleObject;
+ }
+
+ public List<String> getStringList() {
+ return stringList;
+ }
+
+ public void setStringList(List<String> stringList) {
+ this.stringList = stringList;
+ }
+
+ public Map<String, Float> getFloatMap() {
+ return floatMap;
+ }
+
+ public void setFloatMap(Map<String, Float> floatMap) {
+ this.floatMap = floatMap;
+ }
+
+ public Map<SimpleObject, String> getObjectMap() {
+ return objectMap;
+ }
+
+ public void setObjectMap(Map<SimpleObject, String> objectMap) {
+ this.objectMap = objectMap;
+ }
+
+ public Map<String, Map<String, String>> getMapOfMaps() {
+ return mapOfMaps;
+ }
+
+ public void setMapOfMaps(Map<String, Map<String, String>> mapOfMaps) {
+ this.mapOfMaps = mapOfMaps;
+ }
+}
--- /dev/null
+package org.argeo.jcr;
+
+import java.io.File;
+
+import javax.jcr.Node;
+
+import org.argeo.server.jackrabbit.unit.AbstractJcrTestCase;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+public class MapperTest extends AbstractJcrTestCase {
+ public void testSimpleObject() throws Exception {
+ SimpleObject mySo = new SimpleObject();
+ mySo.setInteger(100);
+ mySo.setString("hello world");
+
+ OtherObject oo1 = new OtherObject();
+ oo1.setKey("someKey");
+ oo1.setValue("stringValue");
+ mySo.setOtherObject(oo1);
+
+ OtherObject oo2 = new OtherObject();
+ oo2.setKey("anotherSimpleObject");
+ oo2.setValue(new SimpleObject());
+ mySo.setAnotherObject(oo2);
+
+ BeanNodeMapper bnm = new BeanNodeMapper();
+
+ Node node = bnm.save(session(), mySo);
+ session().save();
+ JcrUtils.debug(node);
+ }
+
+ protected File getRepositoryFile() throws Exception {
+ Resource res = new ClassPathResource(
+ "org/argeo/server/jcr/repository-inMemory.xml");
+ return res.getFile();
+ }
+
+}
--- /dev/null
+package org.argeo.jcr;
+
+public class OtherObject {
+ private String key;
+ private Object value;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+}
--- /dev/null
+package org.argeo.jcr;
+
+import java.util.UUID;
+
+public class SimpleObject {
+ private String string;
+ private String uuid = UUID.randomUUID().toString();
+ private Integer integer;
+ private OtherObject otherObject;
+ private OtherObject anotherObject;
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String sting) {
+ this.string = sting;
+ }
+
+ public Integer getInteger() {
+ return integer;
+ }
+
+ public void setInteger(Integer integer) {
+ this.integer = integer;
+ }
+
+ public OtherObject getOtherObject() {
+ return otherObject;
+ }
+
+ public void setOtherObject(OtherObject otherObject) {
+ this.otherObject = otherObject;
+ }
+
+ public OtherObject getAnotherObject() {
+ return anotherObject;
+ }
+
+ public void setAnotherObject(OtherObject anotherObject) {
+ this.anotherObject = anotherObject;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return string.equals(((SimpleObject) obj).string);
+ }
+
+ @Override
+ public int hashCode() {
+ return string.hashCode();
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+}
--- /dev/null
+package org.argeo.server.jcr;
+
+import java.io.File;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.server.jackrabbit.unit.AbstractJcrTestCase;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+public class JcrResourceAdapterTest extends AbstractJcrTestCase {
+ private static SimpleDateFormat sdf = new SimpleDateFormat(
+ "yyyyMMdd:hhmmss.SSS");
+
+ private final static Log log = LogFactory
+ .getLog(JcrResourceAdapterTest.class);
+
+ private JcrResourceAdapter jra;
+
+ public void testCreate() throws Exception {
+ String basePath = "/test/subdir";
+ jra.mkdirs(basePath);
+ Resource res = new ClassPathResource("org/argeo/server/jcr/dummy00.xls");
+ String filePath = basePath + "/dummy.xml";
+ jra.create(filePath, res, "application/vnd.ms-excel");
+ InputStream in = jra.retrieve(filePath);
+ assertTrue(IOUtils.contentEquals(res.getInputStream(), in));
+ }
+
+ public void testVersioning() throws Exception {
+ String basePath = "/test/versions";
+ jra.mkdirs(basePath);
+ String filePath = basePath + "/dummy.xml";
+ Resource res00 = new ClassPathResource(
+ "org/argeo/server/jcr/dummy00.xls");
+ jra.create(filePath, res00, "application/vnd.ms-excel");
+ Resource res01 = new ClassPathResource(
+ "org/argeo/server/jcr/dummy01.xls");
+ jra.update(filePath, res01);
+ Resource res02 = new ClassPathResource(
+ "org/argeo/server/jcr/dummy02.xls");
+ jra.update(filePath, res02);
+
+ List<Calendar> versions = jra.listVersions(filePath);
+ log.debug("Versions of " + filePath);
+ int count = 0;
+ for (Calendar version : versions) {
+ log.debug(" " + (count == 0 ? "base" : count - 1) + "\t"
+ + sdf.format(version.getTime()));
+ count++;
+ }
+
+ assertEquals(4, versions.size());
+
+ InputStream in = jra.retrieve(filePath, 1);
+ assertTrue(IOUtils.contentEquals(res01.getInputStream(), in));
+ in = jra.retrieve(filePath, 0);
+ assertTrue(IOUtils.contentEquals(res00.getInputStream(), in));
+ in = jra.retrieve(filePath, 2);
+ assertTrue(IOUtils.contentEquals(res02.getInputStream(), in));
+ Resource res03 = new ClassPathResource(
+ "org/argeo/server/jcr/dummy03.xls");
+ jra.update(filePath, res03);
+ in = jra.retrieve(filePath, 1);
+ assertTrue(IOUtils.contentEquals(res01.getInputStream(), in));
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ jra = new JcrResourceAdapter();
+ jra.setRepository(getRepository());
+ jra.setUsername("demo");
+ jra.setPassword("demo");
+ jra.afterPropertiesSet();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ jra.destroy();
+ super.tearDown();
+ }
+
+ protected File getRepositoryFile() throws Exception {
+ Resource res = new ClassPathResource(
+ "org/argeo/server/jcr/repository-inMemory.xml");
+ return res.getFile();
+ }
+
+}
--- /dev/null
+log4j.rootLogger=WARN, console
+
+## Levels
+log4j.logger.org.argeo=DEBUG
+log4j.logger.org.apache.jackrabbit=OFF
+
+## Appenders
+# console is set to be a ConsoleAppender.
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+
+# console uses PatternLayout.
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c%n
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
+\r
+ <bean\r
+ class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">\r
+ <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />\r
+ <property name="ignoreUnresolvablePlaceholders" value="true" />\r
+ </bean>\r
+\r
+ <bean id="nodeMapperProvider" class="org.argeo.slc.jcr.dao.SlcNodeMapperProvider"\r
+ init-method="init">\r
+ <property name="defaultNodeMapper" ref="nodeMapper" />\r
+ <property name="treeTestResultNodeMapper" ref="treeTestResultNodeMapper" />\r
+ </bean>\r
+\r
+ <bean id="nodeMapper" class="org.argeo.jcr.BeanNodeMapper">\r
+ </bean>\r
+\r
+ <bean id="treeTestResultNodeMapper" class="org.argeo.slc.jcr.dao.TreeTestResultNodeMapper">\r
+ </bean>\r
+\r
+ <bean id="argeo.jcr.session.inMemory" factory-bean="argeo.jcr.repository.inMemory"\r
+ factory-method="login" destroy-method="logout">\r
+ <constructor-arg>\r
+ <bean class="javax.jcr.SimpleCredentials">\r
+ <constructor-arg value="demo" />\r
+ <constructor-arg value="demo" />\r
+ </bean>\r
+ </constructor-arg>\r
+ </bean>\r
+\r
+ <bean id="argeo.jcr.repository.inMemory" class="org.argeo.server.jackrabbit.JackrabbitContainer">\r
+ <property name="homeDirectory" value="${java.io.tmpdir}/jackrabbit-slc-unit" />\r
+ <property name="configuration"\r
+ value="classpath:/org/argeo/server/jcr/repository-inMemory.xml" />\r
+ </bean>\r
+\r
+</beans>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+ <!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version
+ 2.0 (the "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied. See the License for
+ the specific language governing permissions and limitations under the
+ License.
+ -->
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
+ "http://jackrabbit.apache.org/dtd/repository-1.6.dtd">
+ <!--
+ Example Repository Configuration File Used by -
+ org.apache.jackrabbit.core.config.RepositoryConfigTest.java -
+ -->
+<Repository>
+ <!--
+ virtual file system where the repository stores global state (e.g.
+ registered namespaces, custom node types, etc.)
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/repository" />
+ </FileSystem>
+
+ <!--
+ security configuration
+ -->
+ <Security appName="Jackrabbit">
+ <!--
+ security manager: class: FQN of class implementing the
+ JackrabbitSecurityManager interface
+ -->
+ <SecurityManager
+ class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager"
+ workspaceName="security">
+ <!--
+ workspace access: class: FQN of class implementing the
+ WorkspaceAccessManager interface
+ -->
+ <!-- <WorkspaceAccessManager class="..."/> -->
+ <!-- <param name="config" value="${rep.home}/security.xml"/> -->
+ </SecurityManager>
+
+ <!--
+ access manager: class: FQN of class implementing the AccessManager
+ interface
+ -->
+ <AccessManager
+ class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
+ <!-- <param name="config" value="${rep.home}/access.xml"/> -->
+ </AccessManager>
+
+ <LoginModule
+ class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
+ <!--
+ anonymous user name ('anonymous' is the default value)
+ -->
+ <param name="anonymousId" value="anonymous" />
+ <!--
+ administrator user id (default value if param is missing is 'admin')
+ -->
+ <param name="adminId" value="admin" />
+ </LoginModule>
+ </Security>
+
+ <!--
+ location of workspaces root directory and name of default workspace
+ -->
+ <Workspaces rootPath="${rep.home}/workspaces"
+ defaultWorkspace="default" />
+ <!--
+ workspace configuration template: used to create the initial workspace
+ if there's no workspace yet
+ -->
+ <Workspace name="${wsp.name}">
+ <!--
+ virtual file system of the workspace: class: FQN of class
+ implementing the FileSystem interface
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${wsp.home}" />
+ </FileSystem>
+ <!--
+ persistence manager of the workspace: class: FQN of class
+ implementing the PersistenceManager interface
+ -->
+ <PersistenceManager
+ class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+ <!--
+ <param name="url" value="jdbc:derby:memory:db;create=true" />
+ -->
+ <param name="url" value="jdbc:derby:${wsp.home}/db;create=true" />
+ <param name="driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
+ <param name="schemaObjectPrefix" value="${wsp.name}_" />
+ </PersistenceManager>
+ <!--
+ Search index and the file system it uses. class: FQN of class
+ implementing the QueryHandler interface
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${wsp.home}/index" />
+ <param name="extractorPoolSize" value="2" />
+ <param name="supportHighlighting" value="true" />
+ </SearchIndex>
+ </Workspace>
+
+ <!--
+ Configures the versioning
+ -->
+ <Versioning rootPath="${rep.home}/version">
+ <!--
+ Configures the filesystem to use for versioning for the respective
+ persistence manager
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/version" />
+ </FileSystem>
+
+ <!--
+ Configures the persistence manager to be used for persisting version
+ state. Please note that the current versioning implementation is
+ based on a 'normal' persistence manager, but this could change in
+ future implementations.
+ -->
+ <PersistenceManager
+ class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+ <!--
+ <param name="url" value="jdbc:derby:memory:version;create=true" />
+ -->
+ <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true" />
+ <param name="driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
+ <param name="schemaObjectPrefix" value="version_" />
+ </PersistenceManager>
+ </Versioning>
+
+ <!--
+ Search index for content that is shared repository wide (/jcr:system
+ tree, contains mainly versions)
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index" />
+ <param name="extractorPoolSize" value="2" />
+ <param name="supportHighlighting" value="true" />
+ </SearchIndex>
+</Repository>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
+ "http://jackrabbit.apache.org/dtd/repository-1.6.dtd">
+<!-- Example Repository Configuration File
+ Used by
+ - org.apache.jackrabbit.core.config.RepositoryConfigTest.java
+ -
+-->
+<Repository>
+ <!--
+ virtual file system where the repository stores global state
+ (e.g. registered namespaces, custom node types, etc.)
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/repository"/>
+ </FileSystem>
+
+ <!--
+ security configuration
+ -->
+ <Security appName="Jackrabbit">
+ <!--
+ security manager:
+ class: FQN of class implementing the JackrabbitSecurityManager interface
+ -->
+ <SecurityManager class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager" workspaceName="security">
+ <!--
+ workspace access:
+ class: FQN of class implementing the WorkspaceAccessManager interface
+ -->
+ <!-- <WorkspaceAccessManager class="..."/> -->
+ <!-- <param name="config" value="${rep.home}/security.xml"/> -->
+ </SecurityManager>
+
+ <!--
+ access manager:
+ class: FQN of class implementing the AccessManager interface
+ -->
+ <AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
+ <!-- <param name="config" value="${rep.home}/access.xml"/> -->
+ </AccessManager>
+
+ <LoginModule class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
+ <!--
+ anonymous user name ('anonymous' is the default value)
+ -->
+ <param name="anonymousId" value="anonymous"/>
+ <!--
+ administrator user id (default value if param is missing is 'admin')
+ -->
+ <param name="adminId" value="admin"/>
+ </LoginModule>
+ </Security>
+
+ <!--
+ location of workspaces root directory and name of default workspace
+ -->
+ <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
+ <!--
+ workspace configuration template:
+ used to create the initial workspace if there's no workspace yet
+ -->
+ <Workspace name="${wsp.name}">
+ <!--
+ virtual file system of the workspace:
+ class: FQN of class implementing the FileSystem interface
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${wsp.home}"/>
+ </FileSystem>
+ <!--
+ persistence manager of the workspace:
+ class: FQN of class implementing the PersistenceManager interface
+ -->
+ <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+ <param name="url" value="jdbc:derby:memory:db;create=true"/>
+ <param name="schemaObjectPrefix" value="${wsp.name}_"/>
+ </PersistenceManager>
+ <!--
+ Search index and the file system it uses.
+ class: FQN of class implementing the QueryHandler interface
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${wsp.home}/index"/>
+ <param name="extractorPoolSize" value="2"/>
+ <param name="supportHighlighting" value="true"/>
+ </SearchIndex>
+ </Workspace>
+
+ <!--
+ Configures the versioning
+ -->
+ <Versioning rootPath="${rep.home}/version">
+ <!--
+ Configures the filesystem to use for versioning for the respective
+ persistence manager
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/version" />
+ </FileSystem>
+
+ <!--
+ Configures the persistence manager to be used for persisting version state.
+ Please note that the current versioning implementation is based on
+ a 'normal' persistence manager, but this could change in future
+ implementations.
+ -->
+ <PersistenceManager class="org.apache.jackrabbit.core.persistence.bundle.DerbyPersistenceManager">
+ <param name="url" value="jdbc:derby:memory:version;create=true"/>
+ <param name="schemaObjectPrefix" value="version_"/>
+ </PersistenceManager>
+ </Versioning>
+
+ <!--
+ Search index for content that is shared repository wide
+ (/jcr:system tree, contains mainly versions)
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index"/>
+ <param name="extractorPoolSize" value="2"/>
+ <param name="supportHighlighting" value="true"/>
+ </SearchIndex>
+</Repository>