import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
-//import org.springframework.beans.BeanWrapperImpl;
-
-public class BeanNodeMapper {
+public class BeanNodeMapper implements NodeMapper {
private final static Log log = LogFactory.getLog(BeanNodeMapper.class);
private final static String NODE_VALUE = "value";
private Boolean versioning = false;
private Boolean strictUuidReference = false;
+
+ // TODO define a primaryNodeType Strategy
private String primaryNodeType = null;
private ClassLoader classLoader = getClass().getClassLoader();
- 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();
- }
+ private NodeMapperProvider nodeMapperProvider;
- public Node save(Session session, Object obj) {
- return save(session, storagePath(obj), obj);
+ /**
+ * 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 {
- beanToNode(createBeanWrapper(obj), node);
+ 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 {
BeanWrapper beanWrapper = createBeanWrapper(obj);
Node parentNode;
if (session.itemExists(path))
parentNode = (Node) session.getItem(parentPath);
- else
+ 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));
- beanToNode(beanWrapper, node);
+ // 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;
}
}
+ /**
+ * 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")
- public Object nodeToBean(Node node) throws RepositoryException {
+ /**
+ * Transforms a node into an object of the class defined by classProperty Property
+ */
+ protected Object nodeToBean(Node node) throws RepositoryException {
String clssName = node.getProperty(classProperty).getValue()
.getString();
- if (log.isDebugEnabled())
- log.debug("Map node " + node.getPath() + " to bean " + clssName);
-
BeanWrapper beanWrapper = createBeanWrapper(loadClass(clssName));
// process properties
.getName());
Class propClass = pd.getPropertyType();
- // list
+ // Process case of List and its derived classes
+ // primitive list
if (propClass != null && List.class.isAssignableFrom(propClass)) {
List<Object> lst = new ArrayList<Object>();
Class<?> valuesClass = classFromProperty(prop);
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);
PropertyDescriptor pd = beanWrapper.getPropertyDescriptor(name);
Class propClass = pd.getPropertyType();
- log.debug(childNode.getName() + "=" + propClass);
-
+ // objects list
if (propClass != null && List.class.isAssignableFrom(propClass)) {
String lstClass = childNode.getProperty(classProperty)
.getString();
continue nodes;
}
+ // objects map
if (propClass != null && Map.class.isAssignableFrom(propClass)) {
String mapClass = childNode.getProperty(classProperty)
.getString();
return beanWrapper.getWrappedInstance();
}
+ /**
+ * 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 {
- if (log.isDebugEnabled())
- log.debug("Map bean to node " + node.getPath());
-
properties: for (PropertyDescriptor pd : beanWrapper
.getPropertyDescriptors()) {
String name = pd.getName();
-
if (!beanWrapper.isReadableProperty(name))
continue properties;// skip
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;
}
}
+ /**
+ * 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
}
}
+ /**
+ * 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
}
protected Class<?> loadClass(String name) {
+ // log.debug("Class loader: " + classLoader);
try {
return classLoader.loadClass(name);
} catch (ClassNotFoundException e) {
this.classLoader = classLoader;
}
+ public void setNodeMapperProvider(NodeMapperProvider nodeMapperProvider) {
+ this.nodeMapperProvider = nodeMapperProvider;
+ }
+
+ public String getPrimaryNodeType() {
+ return this.primaryNodeType;
+ }
+
+ public String getClassProperty() {
+ return this.classProperty;
+ }
}