From 22365726e2fdcb12e76c3d78060960ae7161628e Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 14 Oct 2011 18:18:20 +0000 Subject: [PATCH] Improve JCR remoting and proxying git-svn-id: https://svn.argeo.org/commons/trunk@4841 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- pom.xml | 4 +- .../org.argeo.security.dao.ldap/pom.xml | 3 +- .../noderepo.properties | 4 +- .../AbstractJackrabbitHandlerMapping.java | 1 + .../remote/ExtendedDispatcherServlet.java | 20 ++- .../remote/SimpleSessionProvider.java | 52 ++++--- .../remote/SimpleWebdavServlet.java | 2 +- .../mvc/MultipleRepositoryHandlerMapping.java | 23 +-- .../argeo/jcr/mvc/ResourceProxyServlet.java | 12 +- .../src/main/java/org/argeo/jcr/JcrUtils.java | 144 ++++++++++++++++-- .../jcr/ThreadBoundJcrSessionFactory.java | 2 +- .../org/argeo/jcr/proxy/AbstractUrlProxy.java | 72 ++++----- .../main/resources/org/argeo/jcr/argeo.cnd | 3 + 13 files changed, 232 insertions(+), 110 deletions(-) diff --git a/pom.xml b/pom.xml index c7011d39e..74f85b05f 100644 --- a/pom.xml +++ b/pom.xml @@ -382,12 +382,12 @@ limitations under the License. localrepo Internal Release Repository - dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/slc/repo/artifacts + dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/repo localrepo.snapshots Internal Snapshot Repository - dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/slc/repo/artifacts + dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/repo diff --git a/security/modules/org.argeo.security.dao.ldap/pom.xml b/security/modules/org.argeo.security.dao.ldap/pom.xml index 88358854d..91058b37f 100644 --- a/security/modules/org.argeo.security.dao.ldap/pom.xml +++ b/security/modules/org.argeo.security.dao.ldap/pom.xml @@ -20,7 +20,8 @@ *, org.argeo.jcr, com.sun.jndi.ldap;resolution:=optional, - org.springframework.ldap.core.support + org.springframework.ldap.core.support, + org.springframework.security diff --git a/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties b/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties index a6c5b4bdc..046e1790a 100644 --- a/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties +++ b/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties @@ -2,11 +2,11 @@ argeo.node.repo.workspace=dev # Repository base directory -argeo.node.repo.home=${osgi.instance.area}/node/repo +argeo.node.repo.home=${osgi.instance.area}/node ## H2 Embedded (DEFAULT) argeo.node.repo.configuration=osgibundle:repository-h2.xml -argeo.node.repo.dburl=jdbc:h2:${osgi.instance.area}/node/h2/repo +argeo.node.repo.dburl=jdbc:h2:${osgi.instance.area}/node/h2/repository argeo.node.repo.dbuser=sa argeo.node.repo.dbpassword= diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java index 5c0ef8313..ae0008681 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/AbstractJackrabbitHandlerMapping.java @@ -3,6 +3,7 @@ package org.argeo.jackrabbit.remote; import org.apache.jackrabbit.server.SessionProvider; import org.argeo.jcr.mvc.MultipleRepositoryHandlerMapping; +/** Base class for Jackrabbit ahndler mappings. */ public abstract class AbstractJackrabbitHandlerMapping extends MultipleRepositoryHandlerMapping { private SessionProvider sessionProvider; diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java index cff2c3b01..e11087794 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/ExtendedDispatcherServlet.java @@ -37,16 +37,20 @@ public class ExtendedDispatcherServlet extends DispatcherServlet { // see http://forum.springsource.org/showthread.php?t=53472 try { - if (log.isTraceEnabled()) - log.trace("Received request " + request); -// log.debug("PathTranslated="+request.getPathTranslated()); - log.debug("PathInfo="+request.getPathInfo()); -// log.debug("ServletPath="+request.getServletPath()); -// log.debug("ContextPath="+request.getContextPath()); + if (log.isTraceEnabled()) { + log.trace("UserPrincipal = " + + request.getUserPrincipal().getName()); + log.trace("SessionID = " + request.getSession().getId()); + log.trace("ContextPath = " + request.getContextPath()); + log.trace("ServletPath = " + request.getServletPath()); + log.trace("PathInfo = " + request.getPathInfo()); + log.trace("Method = " + request.getMethod()); + log.trace("User-Agent = " + request.getHeader("User-Agent")); + } doService(request, response); } catch (Exception e) { -// e.printStackTrace(); -// log.debug(request.getMethod()); + // e.printStackTrace(); + // log.debug(request.getMethod()); throw new ArgeoException("Cannot process request", e); } } diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java index aa9bfa5d6..6647eb94b 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleSessionProvider.java @@ -16,6 +16,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.jackrabbit.server.SessionProvider; import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; /** To be injected, typically of scope="session" */ public class SimpleSessionProvider implements SessionProvider, Serializable { @@ -26,39 +27,48 @@ public class SimpleSessionProvider implements SessionProvider, Serializable { private transient Map sessions; + private Boolean openSessionInView = true; + public Session getSession(HttpServletRequest request, Repository rep, String workspace) throws LoginException, ServletException, RepositoryException { - // since sessions is transient it can't be restored from the session - if (sessions == null) - sessions = Collections - .synchronizedMap(new HashMap()); - if (!sessions.containsKey(workspace)) { - try { - Session session = rep.login(null, workspace); - if (log.isTraceEnabled()) - log.trace("User " + session.getUserID() + " logged into " - + request.getServletPath()); - sessions.put(workspace, session); - return session; - } catch (Exception e) { - throw new ArgeoException("Cannot open session", e); - } + if (openSessionInView) { + return rep.login(workspace); } else { - Session session = sessions.get(workspace); - if (!session.isLive()) { - sessions.remove(workspace); - session = rep.login(null, workspace); - sessions.put(workspace, session); + // since sessions is transient it can't be restored from the session + if (sessions == null) + sessions = Collections + .synchronizedMap(new HashMap()); + + if (!sessions.containsKey(workspace)) { + try { + Session session = rep.login(null, workspace); + if (log.isTraceEnabled()) + log.trace("User " + session.getUserID() + + " logged into " + request.getServletPath()); + sessions.put(workspace, session); + return session; + } catch (Exception e) { + throw new ArgeoException("Cannot open session", e); + } + } else { + Session session = sessions.get(workspace); + if (!session.isLive()) { + sessions.remove(workspace); + session = rep.login(null, workspace); + sessions.put(workspace, session); + } + return session; } - return session; } } public void releaseSession(Session session) { if (log.isTraceEnabled()) log.trace("Releasing JCR session " + session); + if (openSessionInView) + JcrUtils.logoutQuietly(session); } public void init() { diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java index 6bc48fa07..02f1fd371 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/remote/SimpleWebdavServlet.java @@ -20,7 +20,7 @@ import javax.jcr.Repository; import org.apache.jackrabbit.server.SessionProvider; -/** WebDav servlet whoe repository is injected */ +/** WebDav servlet whose repository is injected */ public class SimpleWebdavServlet extends org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet { private static final long serialVersionUID = -369787931175177080L; diff --git a/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/MultipleRepositoryHandlerMapping.java b/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/MultipleRepositoryHandlerMapping.java index bc333ba44..bd5b37005 100644 --- a/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/MultipleRepositoryHandlerMapping.java +++ b/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/MultipleRepositoryHandlerMapping.java @@ -1,6 +1,5 @@ package org.argeo.jcr.mvc; -import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Properties; @@ -15,6 +14,7 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; import org.argeo.jcr.RepositoryRegister; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; @@ -51,26 +51,7 @@ public abstract class MultipleRepositoryHandlerMapping implements String pathInfo = request.getPathInfo(); // tokenize path - // TODO factorize - List tokens = new ArrayList(); - StringBuffer curr = new StringBuffer(); - char[] arr = pathInfo.toCharArray(); - chars: for (int i = 0; i < arr.length; i++) { - char c = arr[i]; - if (c == '/') { - if (i == 0 || (i == arr.length - 1)) - continue chars; - if (curr.length() > 0) { - tokens.add(curr.toString()); - curr = new StringBuffer(); - } - } else - curr.append(c); - } - if (curr.length() > 0) { - tokens.add(curr.toString()); - curr = new StringBuffer(); - } + List tokens = JcrUtils.tokenize(pathInfo); // check if repository can be found if (tokens.size() == 0 diff --git a/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/ResourceProxyServlet.java b/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/ResourceProxyServlet.java index 20306609f..b92f776cd 100644 --- a/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/ResourceProxyServlet.java +++ b/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/ResourceProxyServlet.java @@ -40,8 +40,16 @@ public class ResourceProxyServlet extends HttpServlet implements ArgeoNames { String path = request.getPathInfo(); String nodePath = proxy.getNodePath(path); - if (log.isTraceEnabled()) + if (log.isTraceEnabled()) { log.trace("path=" + path + ", nodePath=" + nodePath); + log.trace("UserPrincipal = " + request.getUserPrincipal().getName()); + log.trace("SessionID = " + request.getSession().getId()); + log.trace("ContextPath = " + request.getContextPath()); + log.trace("ServletPath = " + request.getServletPath()); + log.trace("PathInfo = " + request.getPathInfo()); + log.trace("Method = " + request.getMethod()); + log.trace("User-Agent = " + request.getHeader("User-Agent")); + } Node node = proxy.proxy(jcrSession, path); if (node == null) @@ -87,7 +95,7 @@ public class ResourceProxyServlet extends HttpServlet implements ArgeoNames { binary = node.getNode(Property.JCR_CONTENT) .getProperty(Property.JCR_DATA).getBinary(); } catch (PathNotFoundException e) { - log.error("Node "+node+" as no data under content"); + log.error("Node " + node + " as no data under content"); throw e; } in = binary.getStream(); 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 index eeaff3a92..5efc24049 100644 --- 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 @@ -23,14 +23,15 @@ import java.net.MalformedURLException; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.StringTokenizer; import java.util.TreeMap; import javax.jcr.Binary; @@ -144,6 +145,46 @@ public class JcrUtils implements ArgeoJcrConstants { } } + /** Set the {@link NodeType#NT_ADDRESS} properties based on this URL. */ + public static void urlToAddressProperties(Node node, String url) { + try { + URL u = new URL(url); + node.setProperty(Property.JCR_PROTOCOL, u.getProtocol()); + node.setProperty(Property.JCR_HOST, u.getHost()); + node.setProperty(Property.JCR_PORT, Integer.toString(u.getPort())); + node.setProperty(Property.JCR_PATH, normalizePath(u.getPath())); + } catch (Exception e) { + throw new ArgeoException("Cannot set URL " + url + + " as nt:address properties", e); + } + } + + /** Build URL based on the {@link NodeType#NT_ADDRESS} properties. */ + public static String urlFromAddressProperties(Node node) { + try { + URL u = new URL( + node.getProperty(Property.JCR_PROTOCOL).getString(), node + .getProperty(Property.JCR_HOST).getString(), + (int) node.getProperty(Property.JCR_PORT).getLong(), node + .getProperty(Property.JCR_PATH).getString()); + return u.toString(); + } catch (Exception e) { + throw new ArgeoException( + "Cannot get URL from nt:address properties of " + node, e); + } + } + + /** Make sure that: starts with '/', do not end with '/', do not have '//' */ + public static String normalizePath(String path) { + List tokens = tokenize(path); + StringBuffer buf = new StringBuffer(path.length()); + for (String token : tokens) { + buf.append('/'); + buf.append(token); + } + return buf.toString(); + } + /** * Creates a path from a FQDN, inverting the order of the component: * www.argeo.org => org.argeo.www @@ -268,9 +309,33 @@ public class JcrUtils implements ArgeoJcrConstants { return mkdirs(session, path, type, null, false); } + /** + * Synchronized and save is performed, to avoid race conditions in + * initializers leading to duplicate nodes. + */ + public synchronized static Node mkdirsSafe(Session session, String path, + String type) { + try { + if (session.hasPendingChanges()) + throw new ArgeoException( + "Session has pending changes, save them first."); + Node node = mkdirs(session, path, type); + session.save(); + return node; + } catch (RepositoryException e) { + discardQuietly(session); + throw new ArgeoException("Cannot safely make directories", e); + } + } + + public synchronized static Node mkdirsSafe(Session session, String path) { + return mkdirsSafe(session, path, null); + } + /** * Creates the nodes making path, if they don't exist. This is up to the - * caller to save the session. + * caller to save the session. Use with caution since it can create + * duplicate nodes if used concurrently. */ public static Node mkdirs(Session session, String path, String type, String intermediaryNodeType, Boolean versioning) { @@ -291,16 +356,16 @@ public class JcrUtils implements ArgeoJcrConstants { return node; } - StringTokenizer st = new StringTokenizer(path, "/"); StringBuffer current = new StringBuffer("/"); Node currentNode = session.getRootNode(); - while (st.hasMoreTokens()) { - String part = st.nextToken(); + Iterator it = tokenize(path).iterator(); + while (it.hasNext()) { + String part = it.next(); current.append(part).append('/'); if (!session.itemExists(current.toString())) { - if (!st.hasMoreTokens() && type != null) + if (!it.hasNext() && type != null) currentNode = currentNode.addNode(part, type); - else if (st.hasMoreTokens() && intermediaryNodeType != null) + else if (it.hasNext() && intermediaryNodeType != null) currentNode = currentNode.addNode(part, intermediaryNodeType); else @@ -313,13 +378,47 @@ public class JcrUtils implements ArgeoJcrConstants { currentNode = (Node) session.getItem(current.toString()); } } - // session.save(); return currentNode; } catch (RepositoryException e) { + discardQuietly(session); throw new ArgeoException("Cannot mkdirs " + path, e); + } finally { } } + /** Convert a path to the list of its tokens */ + public static List tokenize(String path) { + List tokens = new ArrayList(); + boolean optimized = false; + if (!optimized) { + String[] rawTokens = path.split("/"); + for (String token : rawTokens) { + if (!token.equals("")) + tokens.add(token); + } + } else { + StringBuffer curr = new StringBuffer(); + char[] arr = path.toCharArray(); + chars: for (int i = 0; i < arr.length; i++) { + char c = arr[i]; + if (c == '/') { + if (i == 0 || (i == arr.length - 1)) + continue chars; + if (curr.length() > 0) { + tokens.add(curr.toString()); + curr = new StringBuffer(); + } + } else + curr.append(c); + } + if (curr.length() > 0) { + tokens.add(curr.toString()); + curr = new StringBuffer(); + } + } + return Collections.unmodifiableList(tokens); + } + /** * Safe and repository implementation independent registration of a * namespace. @@ -996,14 +1095,29 @@ public class JcrUtils implements ArgeoJcrConstants { */ public static void updateLastModified(Node node) { try { - if (node.isNodeType(NodeType.MIX_LAST_MODIFIED)) { - node.setProperty(Property.JCR_LAST_MODIFIED, - new GregorianCalendar()); - node.setProperty(Property.JCR_LAST_MODIFIED_BY, node - .getSession().getUserID()); - } + if (!node.isNodeType(NodeType.MIX_LAST_MODIFIED)) + node.addMixin(NodeType.MIX_LAST_MODIFIED); + node.setProperty(Property.JCR_LAST_MODIFIED, + new GregorianCalendar()); + node.setProperty(Property.JCR_LAST_MODIFIED_BY, node.getSession() + .getUserID()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot update last modified on " + node, + e); + } + } + + /** Update lastModified recursively until this parent. */ + public static void updateLastModifiedAndParents(Node node, String untilPath) { + try { + if (!node.getPath().startsWith(untilPath)) + throw new ArgeoException(node + " is not under " + untilPath); + updateLastModified(node); + if (!node.getPath().equals(untilPath)) + updateLastModifiedAndParents(node.getParent(), untilPath); } catch (RepositoryException e) { - throw new ArgeoException("Cannot update last modified", e); + throw new ArgeoException("Cannot update lastModified from " + node + + " until " + untilPath, e); } } 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 index 8adbae784..fc9bcaa86 100644 --- 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 @@ -140,7 +140,7 @@ public abstract class ThreadBoundJcrSessionFactory { deactivate(); for (Session sess : activeSessions.values()) { - sess.logout(); + JcrUtils.logoutQuietly(sess); } activeSessions.clear(); } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/proxy/AbstractUrlProxy.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/proxy/AbstractUrlProxy.java index 7bec5ee7a..357ec1f37 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/proxy/AbstractUrlProxy.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/proxy/AbstractUrlProxy.java @@ -24,15 +24,15 @@ public abstract class AbstractUrlProxy implements ResourceProxy { private Repository jcrRepository; private Session jcrAdminSession; - protected abstract String retrieve(String relativePath); + protected abstract Node retrieve(Session session, String relativePath); void init() { try { jcrAdminSession = jcrRepository.login(); - beforeInitSessionSave(); + beforeInitSessionSave(jcrAdminSession); if (jcrAdminSession.hasPendingChanges()) jcrAdminSession.save(); - } catch (RepositoryException e) { + } catch (Exception e) { JcrUtils.discardQuietly(jcrAdminSession); throw new ArgeoException("Cannot initialize Maven proxy", e); } @@ -42,7 +42,8 @@ public abstract class AbstractUrlProxy implements ResourceProxy { * Called before the (admin) session is saved at the end of the * initialization. Does nothing by default, to be overridden. */ - protected void beforeInitSessionSave() throws RepositoryException { + protected void beforeInitSessionSave(Session session) + throws RepositoryException { } void destroy() { @@ -56,76 +57,75 @@ public abstract class AbstractUrlProxy implements ResourceProxy { protected void beforeDestroySessionLogout() throws RepositoryException { } - public Node proxy(Session jcrSession, String path) { - Node node; + public Node proxy(Session session, String path) { try { + if (session.hasPendingChanges()) + throw new ArgeoException( + "Cannot proxy based on a session with pending changes"); String nodePath = getNodePath(path); - if (!jcrSession.itemExists(nodePath)) { - String nodeIdentifier = retrieve(path); - if (nodeIdentifier == null) { - // log.warn("Could not proxy " + path); + if (!session.itemExists(nodePath)) { + Node nodeT = retrieveAndSave(path); + if (nodeT == null) return null; - } else { - node = jcrSession.getNodeByIdentifier(nodeIdentifier); - } - } else { - node = jcrSession.getNode(nodePath); } + return session.getNode(nodePath); } catch (RepositoryException e) { + JcrUtils.discardQuietly(jcrAdminSession); throw new ArgeoException("Cannot proxy " + path, e); } - return node; } - protected Node proxyUrl(String baseUrl, String path) { + protected synchronized Node retrieveAndSave(String path) { + try { + Node node = retrieve(jcrAdminSession, path); + if (node == null) + return null; + jcrAdminSession.save(); + return node; + } catch (RepositoryException e) { + JcrUtils.discardQuietly(jcrAdminSession); + throw new ArgeoException("Cannot retrieve and save " + path, e); + } + } + + /** Session is not saved */ + protected Node proxyUrl(Session session, String baseUrl, String path) { Node node = null; String remoteUrl = baseUrl + path; - if (log.isTraceEnabled()) - log.trace("baseUrl=" + remoteUrl); InputStream in = null; try { URL u = new URL(remoteUrl); in = u.openStream(); - node = importFile(getNodePath(path), in); - if (log.isDebugEnabled()) - log.debug("Imported " + remoteUrl + " to " + node); + node = importFile(session, getNodePath(path), in); } catch (Exception e) { - if (log.isTraceEnabled()) + if (log.isTraceEnabled()) { log.trace("Cannot read " + remoteUrl + ", skipping... " + e.getMessage()); - if (log.isTraceEnabled()) { - log.trace("Cannot read because of ", e); + // log.trace("Cannot read because of ", e); } + JcrUtils.discardQuietly(session); } finally { IOUtils.closeQuietly(in); } - return node; } - protected synchronized Node importFile(String nodePath, InputStream in) { + protected Node importFile(Session session, String nodePath, InputStream in) + throws RepositoryException { // FIXME allow parallel proxying Binary binary = null; try { Node node = JcrUtils.mkdirs(jcrAdminSession, nodePath, NodeType.NT_FILE, NodeType.NT_FOLDER, false); Node content = node.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE); - binary = jcrAdminSession.getValueFactory().createBinary(in); + binary = session.getValueFactory().createBinary(in); content.setProperty(Property.JCR_DATA, binary); - jcrAdminSession.save(); return node; - } catch (RepositoryException e) { - JcrUtils.discardQuietly(jcrAdminSession); - throw new ArgeoException("Cannot initialize Maven proxy", e); } finally { JcrUtils.closeQuietly(binary); } } - protected Session getJcrAdminSession() { - return jcrAdminSession; - } - public void setJcrRepository(Repository jcrRepository) { this.jcrRepository = jcrRepository; } diff --git a/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd b/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd index 48bb997c6..4038dccc2 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd +++ b/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd @@ -6,6 +6,9 @@ mixin // URI(s) - argeo:uri (STRING) m +[argeo:references] > nt:unstructured +- * (REFERENCE) * + // USER NODES // user should be lower case, between 3 and 15 characters long [argeo:userHome] > mix:created, mix:lastModified -- 2.39.2