<repository>
<id>localrepo</id>
<name>Internal Release Repository</name>
- <url>dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/slc/repo/artifacts</url>
+ <url>dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/repo</url>
</repository>
<snapshotRepository>
<id>localrepo.snapshots</id>
<name>Internal Snapshot Repository</name>
- <url>dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/slc/repo/artifacts</url>
+ <url>dav:http://localrepo:7070/org.argeo.jcr.webapp/webdav/node/dev/repo</url>
</snapshotRepository>
</distributionManagement>
</profile>
*,
org.argeo.jcr,
com.sun.jndi.ldap;resolution:=optional,
- org.springframework.ldap.core.support
+ org.springframework.ldap.core.support,
+ org.springframework.security
</Import-Package>
</instructions>
</configuration>
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=
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;
// 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);
}
}
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 {
private transient Map<String, Session> 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<String, Session>());
- 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<String, Session>());
+
+ 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() {
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;
package org.argeo.jcr.mvc;
-import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
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;
String pathInfo = request.getPathInfo();
// tokenize path
- // TODO factorize
- List<String> tokens = new ArrayList<String>();
- 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<String> tokens = JcrUtils.tokenize(pathInfo);
// check if repository can be found
if (tokens.size() == 0
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)
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();
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;
}
}
+ /** 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<String> 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
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) {
return node;
}
- StringTokenizer st = new StringTokenizer(path, "/");
StringBuffer current = new StringBuffer("/");
Node currentNode = session.getRootNode();
- while (st.hasMoreTokens()) {
- String part = st.nextToken();
+ Iterator<String> 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
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<String> tokenize(String path) {
+ List<String> tokens = new ArrayList<String>();
+ 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.
*/
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);
}
}
deactivate();
for (Session sess : activeSessions.values()) {
- sess.logout();
+ JcrUtils.logoutQuietly(sess);
}
activeSessions.clear();
}
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);
}
* 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() {
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;
}
// 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