From: Mathieu Baudier Date: Fri, 30 Apr 2010 08:19:35 +0000 (+0000) Subject: Split server Jackrabbit into JCR X-Git-Tag: argeo-commons-2.1.30~1617 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=a668345e948f3f6da7475279bbe330e129fb1841;p=lgpl%2Fargeo-commons.git Split server Jackrabbit into JCR git-svn-id: https://svn.argeo.org/commons/trunk@3542 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/server/runtime/org.argeo.server.jackrabbit/.classpath b/server/runtime/org.argeo.server.jackrabbit/.classpath index 3e6ecf767..73ba12c2e 100644 --- a/server/runtime/org.argeo.server.jackrabbit/.classpath +++ b/server/runtime/org.argeo.server.jackrabbit/.classpath @@ -2,8 +2,6 @@ - - diff --git a/server/runtime/org.argeo.server.jackrabbit/build.properties b/server/runtime/org.argeo.server.jackrabbit/build.properties index a90395047..fdf424dbc 100644 --- a/server/runtime/org.argeo.server.jackrabbit/build.properties +++ b/server/runtime/org.argeo.server.jackrabbit/build.properties @@ -4,7 +4,8 @@ additional.bundles = com.springsource.slf4j.api,\ 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/,\ diff --git a/server/runtime/org.argeo.server.jackrabbit/repository.xml b/server/runtime/org.argeo.server.jackrabbit/repository.xml deleted file mode 100644 index 666919d28..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/repository.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/ArgeoJcrConstants.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/ArgeoJcrConstants.java deleted file mode 100644 index 4f12fa75a..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/ArgeoJcrConstants.java +++ /dev/null @@ -1,306 +0,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. - */ -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"; -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/BeanNodeMapper.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/BeanNodeMapper.java deleted file mode 100644 index a526bcf5e..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/BeanNodeMapper.java +++ /dev/null @@ -1,604 +0,0 @@ -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 lst = new ArrayList(); - 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 lst; - try { - lst = (List) loadClass(lstClass).newInstance(); - } catch (Exception e) { - lst = new ArrayList(); - } - - 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 map; - try { - map = (Map) loadClass(mapClass) - .newInstance(); - } catch (Exception e) { - map = new HashMap(); - } - - // 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; - } -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/JcrUtils.java deleted file mode 100644 index d3174a1ca..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/JcrUtils.java +++ /dev/null @@ -1,201 +0,0 @@ -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()); - } - } - - } -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/NodeMapper.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/NodeMapper.java deleted file mode 100644 index 2b816c35d..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/NodeMapper.java +++ /dev/null @@ -1,14 +0,0 @@ -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); -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/NodeMapperProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/NodeMapperProvider.java deleted file mode 100644 index 316a877f6..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/NodeMapperProvider.java +++ /dev/null @@ -1,13 +0,0 @@ -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); -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java deleted file mode 100644 index 9996b7bd1..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java +++ /dev/null @@ -1,105 +0,0 @@ -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 activeSessions = Collections - .synchronizedList(new ArrayList()); - - private ThreadLocal session = new ThreadLocal(); - 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 getObjectType() { - return Session.class; - } - - public boolean isSingleton() { - return true; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/unit/AbstractJcrTestCase.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/unit/AbstractJcrTestCase.java index a70c6e9d0..78c477a22 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/unit/AbstractJcrTestCase.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/unit/AbstractJcrTestCase.java @@ -11,13 +11,13 @@ import junit.framework.TestCase; 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"), @@ -44,12 +44,6 @@ public abstract class AbstractJcrTestCase extends TestCase { 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; } diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/DefaultJcrListener.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/DefaultJcrListener.java deleted file mode 100644 index 4b233086d..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/DefaultJcrListener.java +++ /dev/null @@ -1,99 +0,0 @@ -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; - } - -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/JcrResourceAdapter.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/JcrResourceAdapter.java deleted file mode 100644 index 020672b86..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/JcrResourceAdapter.java +++ /dev/null @@ -1,246 +0,0 @@ -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 listVersions(String path) { - if (!versioning) - throw new ArgeoException("Versioning is not activated"); - - try { - List versions = new ArrayList(); - 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; - } -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrBrowserController.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrBrowserController.java deleted file mode 100644 index cddc8b01e..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrBrowserController.java +++ /dev/null @@ -1,74 +0,0 @@ -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 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 paths = new ArrayList(); - while (nit.hasNext()) { - paths.add(nit.nextNode().getPath()); - } - return paths; - } - - @RequestMapping("/queryJcrTable.*") - public List> 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> results = new ArrayList>(); - results.add(Arrays.asList(queryResult.getColumnNames())); - RowIterator rit = queryResult.getRows(); - - while (rit.hasNext()) { - Row row = rit.nextRow(); - List lst = new ArrayList(); - for (Value value : row.getValues()) { - lst.add(value.getString()); - } - } - return results; - } -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrManagerController.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrManagerController.java deleted file mode 100644 index 37fca841c..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrManagerController.java +++ /dev/null @@ -1,79 +0,0 @@ -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 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; - } - -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrMvcConstants.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrMvcConstants.java deleted file mode 100644 index 3f50e9675..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrMvcConstants.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.argeo.server.jcr.mvc; - -public interface JcrMvcConstants { - public final static String REQUEST_ATTR_SESSION = "jcrSession"; -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrXmlServerSerializer.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrXmlServerSerializer.java deleted file mode 100644 index 54cc5b7b5..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/JcrXmlServerSerializer.java +++ /dev/null @@ -1,113 +0,0 @@ -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; - } - -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/OpenSessionInViewJcrInterceptor.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/OpenSessionInViewJcrInterceptor.java deleted file mode 100644 index c91b66dbe..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/mvc/OpenSessionInViewJcrInterceptor.java +++ /dev/null @@ -1,54 +0,0 @@ -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; - } - -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/CollectionsObject.java b/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/CollectionsObject.java deleted file mode 100644 index 5d00c7a10..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/CollectionsObject.java +++ /dev/null @@ -1,72 +0,0 @@ -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 stringList = new ArrayList(); - private Map floatMap = new HashMap(); - private Map objectMap = new HashMap(); - private Map> mapOfMaps = new HashMap>(); - - 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 getStringList() { - return stringList; - } - - public void setStringList(List stringList) { - this.stringList = stringList; - } - - public Map getFloatMap() { - return floatMap; - } - - public void setFloatMap(Map floatMap) { - this.floatMap = floatMap; - } - - public Map getObjectMap() { - return objectMap; - } - - public void setObjectMap(Map objectMap) { - this.objectMap = objectMap; - } - - public Map> getMapOfMaps() { - return mapOfMaps; - } - - public void setMapOfMaps(Map> mapOfMaps) { - this.mapOfMaps = mapOfMaps; - } -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/MapperTest.java b/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/MapperTest.java deleted file mode 100644 index 1b2258266..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/MapperTest.java +++ /dev/null @@ -1,29 +0,0 @@ -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); - } -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/OtherObject.java b/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/OtherObject.java deleted file mode 100644 index a9a49d70a..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/OtherObject.java +++ /dev/null @@ -1,22 +0,0 @@ -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; - } -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/SimpleObject.java b/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/SimpleObject.java deleted file mode 100644 index 29718807a..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/jcr/SimpleObject.java +++ /dev/null @@ -1,62 +0,0 @@ -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; - } - -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java b/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java deleted file mode 100644 index f7e22b964..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java +++ /dev/null @@ -1,88 +0,0 @@ -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 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(); - } - -} diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/log4j.properties b/server/runtime/org.argeo.server.jackrabbit/src/test/resources/log4j.properties deleted file mode 100644 index ca995af8e..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/log4j.properties +++ /dev/null @@ -1,13 +0,0 @@ -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 diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/applicationContext.xml b/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/applicationContext.xml deleted file mode 100644 index 78a34af4d..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/applicationContext.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy00.xls b/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy00.xls deleted file mode 100644 index e5846fef7..000000000 Binary files a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy00.xls and /dev/null differ diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy01.xls b/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy01.xls deleted file mode 100644 index b5c6b5539..000000000 Binary files a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy01.xls and /dev/null differ diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy02.xls b/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy02.xls deleted file mode 100644 index d73bc6605..000000000 Binary files a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy02.xls and /dev/null differ diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy03.xls b/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy03.xls deleted file mode 100644 index 0759cb927..000000000 Binary files a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/dummy03.xls and /dev/null differ diff --git a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/repository.xml b/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/repository.xml deleted file mode 100644 index f05192337..000000000 --- a/server/runtime/org.argeo.server.jackrabbit/src/test/resources/org/argeo/server/jcr/repository.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/server/runtime/org.argeo.server.jcr/.classpath b/server/runtime/org.argeo.server.jcr/.classpath index 8b978d9ed..6cb018918 100644 --- a/server/runtime/org.argeo.server.jcr/.classpath +++ b/server/runtime/org.argeo.server.jcr/.classpath @@ -1,6 +1,8 @@ + + diff --git a/server/runtime/org.argeo.server.jcr/META-INF/MANIFEST.MF b/server/runtime/org.argeo.server.jcr/META-INF/MANIFEST.MF index 202455e14..39e03ff76 100644 --- a/server/runtime/org.argeo.server.jcr/META-INF/MANIFEST.MF +++ b/server/runtime/org.argeo.server.jcr/META-INF/MANIFEST.MF @@ -1,13 +1,45 @@ Manifest-Version: 1.0 Created-By: 1.5.0_16 (Sun Microsystems Inc.) Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt +Import-Package: javax.activation;version="1.1",javax.jcr;version="1.0" + ,javax.jcr.nodetype;version="1.0",javax.jcr.observation;version="1.0" + ,javax.jcr.query;version="1.0",javax.jcr.version;version="1.0",javax. + servlet;version="2.5",javax.servlet.http;version="2.5",javax.xml.pars + ers,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.s + tream,org.apache.commons.fileupload;version="1.2",org.apache.commons. + fileupload.disk;version="1.2",org.apache.commons.fileupload.servlet;v + ersion="1.2",org.apache.commons.io;version="1.4",org.apache.commons.l + ogging;version="1.1",org.argeo;version="0.1",org.argeo.jcr;version="0 + .1",org.argeo.server;version="0.1",org.argeo.server.jcr;version="0.1" + ,org.argeo.server.jcr.mvc;version="0.1",org.argeo.server.mvc;version= + "0.1",org.springframework.beans;version="2.5",org.springframework.bea + ns.factory;version="2.5",org.springframework.core.io;version="2.5",or + g.springframework.stereotype;version="2.5",org.springframework.ui;ver + sion="2.5",org.springframework.web.bind.annotation;version="2.5",org. + springframework.web.context.request;version="2.5",org.springframework + .xml.dom;version="1.5",org.w3c.dom,org.xml.sax Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Bundle-Version: 0.1.3.SNAPSHOT-r3539 +Export-Package: org.argeo.jcr;uses:="org.springframework.beans,javax.j + cr,org.argeo,javax.jcr.query,org.apache.commons.logging,javax.jcr.nod + etype,org.springframework.beans.factory";version="0.1.3.SNAPSHOT-r354 + 0",org.argeo.server.jcr.mvc;uses:="org.springframework.web.context.re + quest,org.springframework.web.bind.annotation,org.springframework.ste + reotype,javax.jcr.query,javax.jcr,javax.servlet.http,org.apache.commo + ns.logging,org.argeo.server,org.apache.commons.fileupload,org.argeo.s + erver.jcr,org.springframework.core.io,org.apache.commons.fileupload.s + ervlet,org.argeo.server.mvc,org.apache.commons.fileupload.disk,org.xm + l.sax,org.w3c.dom,org.argeo,javax.xml.transform,javax.xml.transform.d + om,javax.servlet,org.springframework.xml.dom,javax.xml.parsers,javax. + xml.transform.stream,org.springframework.ui";version="0.1.3.SNAPSHOT- + r3540",org.argeo.server.jcr;uses:="javax.jcr.observation,org.apache.c + ommons.logging,javax.jcr,org.argeo,javax.activation,org.argeo.jcr,org + .springframework.core.io,org.apache.commons.io,javax.jcr.version,org. + springframework.beans.factory";version="0.1.3.SNAPSHOT-r3540" +Bundle-Version: 0.1.3.SNAPSHOT-r3540 Bundle-Name: Commons Server JCR Bundle-DocURL: http://www.argeo.org Bundle-ManifestVersion: 2 Bundle-Vendor: Argeo -Fragment-Host: org.argeo.dep.osgi.jackrabbit Bundle-SymbolicName: org.argeo.server.jcr Tool: Bnd-0.0.357 diff --git a/server/runtime/org.argeo.server.jcr/build.properties b/server/runtime/org.argeo.server.jcr/build.properties index 5fc538bc8..500039909 100644 --- a/server/runtime/org.argeo.server.jcr/build.properties +++ b/server/runtime/org.argeo.server.jcr/build.properties @@ -1,4 +1,16 @@ -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 + diff --git a/server/runtime/org.argeo.server.jcr/pom.xml b/server/runtime/org.argeo.server.jcr/pom.xml index 44b1a1b2f..d4ba29fd8 100644 --- a/server/runtime/org.argeo.server.jcr/pom.xml +++ b/server/runtime/org.argeo.server.jcr/pom.xml @@ -29,7 +29,6 @@ ${version.maven-bundle-plugin} - org.argeo.dep.osgi.jackrabbit org.argeo.jcr.*, org.argeo.server.jcr.* @@ -52,25 +51,10 @@ 0.1.3-SNAPSHOT - + - org.argeo.dep.osgi - org.argeo.dep.osgi.jackrabbit - - - javax.servlet - com.springsource.javax.servlet - - - - - org.apache.commons - com.springsource.org.apache.commons.io - - - - javax.activation - com.springsource.javax.activation + javax.jcr + com.springsource.javax.jcr @@ -94,6 +78,11 @@ org.springframework.xml + + javax.activation + com.springsource.javax.activation + + org.slf4j @@ -112,6 +101,12 @@ + + org.argeo.commons.server + org.argeo.server.jackrabbit + 0.1.3-SNAPSHOT + test + org.argeo.commons.basic org.argeo.support.junit diff --git a/server/runtime/org.argeo.server.jcr/repository.xml b/server/runtime/org.argeo.server.jcr/repository.xml new file mode 100644 index 000000000..666919d28 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/repository.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoJcrConstants.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoJcrConstants.java new file mode 100644 index 000000000..4f12fa75a --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoJcrConstants.java @@ -0,0 +1,306 @@ +/* + * 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"; +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/BeanNodeMapper.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/BeanNodeMapper.java new file mode 100644 index 000000000..a526bcf5e --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/BeanNodeMapper.java @@ -0,0 +1,604 @@ +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 lst = new ArrayList(); + 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 lst; + try { + lst = (List) loadClass(lstClass).newInstance(); + } catch (Exception e) { + lst = new ArrayList(); + } + + 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 map; + try { + map = (Map) loadClass(mapClass) + .newInstance(); + } catch (Exception e) { + map = new HashMap(); + } + + // 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; + } +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java new file mode 100644 index 000000000..d3174a1ca --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -0,0 +1,201 @@ +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()); + } + } + + } +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/NodeMapper.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/NodeMapper.java new file mode 100644 index 000000000..2b816c35d --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/NodeMapper.java @@ -0,0 +1,14 @@ +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); +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/NodeMapperProvider.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/NodeMapperProvider.java new file mode 100644 index 000000000..316a877f6 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/NodeMapperProvider.java @@ -0,0 +1,13 @@ +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); +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java new file mode 100644 index 000000000..9996b7bd1 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java @@ -0,0 +1,105 @@ +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 activeSessions = Collections + .synchronizedList(new ArrayList()); + + private ThreadLocal session = new ThreadLocal(); + 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 getObjectType() { + return Session.class; + } + + public boolean isSingleton() { + return true; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/DefaultJcrListener.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/DefaultJcrListener.java new file mode 100644 index 000000000..4b233086d --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/DefaultJcrListener.java @@ -0,0 +1,99 @@ +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; + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/JcrResourceAdapter.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/JcrResourceAdapter.java new file mode 100644 index 000000000..020672b86 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/JcrResourceAdapter.java @@ -0,0 +1,246 @@ +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 listVersions(String path) { + if (!versioning) + throw new ArgeoException("Versioning is not activated"); + + try { + List versions = new ArrayList(); + 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; + } +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrBrowserController.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrBrowserController.java new file mode 100644 index 000000000..cddc8b01e --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrBrowserController.java @@ -0,0 +1,74 @@ +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 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 paths = new ArrayList(); + while (nit.hasNext()) { + paths.add(nit.nextNode().getPath()); + } + return paths; + } + + @RequestMapping("/queryJcrTable.*") + public List> 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> results = new ArrayList>(); + results.add(Arrays.asList(queryResult.getColumnNames())); + RowIterator rit = queryResult.getRows(); + + while (rit.hasNext()) { + Row row = rit.nextRow(); + List lst = new ArrayList(); + for (Value value : row.getValues()) { + lst.add(value.getString()); + } + } + return results; + } +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrManagerController.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrManagerController.java new file mode 100644 index 000000000..37fca841c --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrManagerController.java @@ -0,0 +1,79 @@ +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 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; + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrMvcConstants.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrMvcConstants.java new file mode 100644 index 000000000..3f50e9675 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrMvcConstants.java @@ -0,0 +1,5 @@ +package org.argeo.server.jcr.mvc; + +public interface JcrMvcConstants { + public final static String REQUEST_ATTR_SESSION = "jcrSession"; +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrXmlServerSerializer.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrXmlServerSerializer.java new file mode 100644 index 000000000..54cc5b7b5 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/JcrXmlServerSerializer.java @@ -0,0 +1,113 @@ +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; + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/OpenSessionInViewJcrInterceptor.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/OpenSessionInViewJcrInterceptor.java new file mode 100644 index 000000000..c91b66dbe --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/server/jcr/mvc/OpenSessionInViewJcrInterceptor.java @@ -0,0 +1,54 @@ +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; + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/CollectionsObject.java b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/CollectionsObject.java new file mode 100644 index 000000000..5d00c7a10 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/CollectionsObject.java @@ -0,0 +1,72 @@ +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 stringList = new ArrayList(); + private Map floatMap = new HashMap(); + private Map objectMap = new HashMap(); + private Map> mapOfMaps = new HashMap>(); + + 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 getStringList() { + return stringList; + } + + public void setStringList(List stringList) { + this.stringList = stringList; + } + + public Map getFloatMap() { + return floatMap; + } + + public void setFloatMap(Map floatMap) { + this.floatMap = floatMap; + } + + public Map getObjectMap() { + return objectMap; + } + + public void setObjectMap(Map objectMap) { + this.objectMap = objectMap; + } + + public Map> getMapOfMaps() { + return mapOfMaps; + } + + public void setMapOfMaps(Map> mapOfMaps) { + this.mapOfMaps = mapOfMaps; + } +} diff --git a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/MapperTest.java b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/MapperTest.java new file mode 100644 index 000000000..cdc8b640f --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/MapperTest.java @@ -0,0 +1,40 @@ +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(); + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/OtherObject.java b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/OtherObject.java new file mode 100644 index 000000000..a9a49d70a --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/OtherObject.java @@ -0,0 +1,22 @@ +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; + } +} diff --git a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/SimpleObject.java b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/SimpleObject.java new file mode 100644 index 000000000..29718807a --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/SimpleObject.java @@ -0,0 +1,62 @@ +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; + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java new file mode 100644 index 000000000..1588fd7e0 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java @@ -0,0 +1,95 @@ +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 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(); + } + +} diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/log4j.properties b/server/runtime/org.argeo.server.jcr/src/test/resources/log4j.properties new file mode 100644 index 000000000..ca995af8e --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/resources/log4j.properties @@ -0,0 +1,13 @@ +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 diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/applicationContext.xml b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/applicationContext.xml new file mode 100644 index 000000000..d40c4650a --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/applicationContext.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy00.xls b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy00.xls new file mode 100644 index 000000000..e5846fef7 Binary files /dev/null and b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy00.xls differ diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy01.xls b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy01.xls new file mode 100644 index 000000000..b5c6b5539 Binary files /dev/null and b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy01.xls differ diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy02.xls b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy02.xls new file mode 100644 index 000000000..d73bc6605 Binary files /dev/null and b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy02.xls differ diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy03.xls b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy03.xls new file mode 100644 index 000000000..0759cb927 Binary files /dev/null and b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/dummy03.xls differ diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository-inMemory.xml b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository-inMemory.xml new file mode 100644 index 000000000..d980f8bd1 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository-inMemory.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository.xml b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository.xml new file mode 100644 index 000000000..f05192337 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +