private final static String JCR_ETAG = "jcr:etag";
private final static String JCR_LAST_MODIFIED = "jcr:lastModified";
private final static String JCR_LAST_MODIFIED_BY = "jcr:lastModifiedBy";
+ private final static String JCR_MIXIN_TYPES = "jcr:mixinTypes";
private final static String JCR_DATA = "jcr:data";
+ private final static String JCR_CONTENT = "jcr:data";
private String cn;
private String workspaceName;
}
private synchronized void processEvents(EventIterator events) {
+ long begin = System.currentTimeMillis();
+ long count = 0;
while (events.hasNext()) {
Event event = events.nextEvent();
processEvent(event);
+ count++;
}
+ long duration = System.currentTimeMillis() - begin;
+ if (log.isTraceEnabled())
+ log.trace("Processed " + count + " events in " + duration + " ms");
notifyAll();
}
protected synchronized void processEvent(Event event) {
try {
+ String eventPath = event.getPath();
if (event.getType() == Event.NODE_ADDED) {
- if (!versionManager.isCheckedOut(event.getPath()))
+ if (!versionManager.isCheckedOut(eventPath))
return;// ignore checked-in nodes
- session.refresh(true);
- Node node = session.getNode(event.getPath());
- if (node.getParent().isNodeType(NodeType.NT_FILE)) {
+ if (log.isTraceEnabled())
+ log.trace("NODE_ADDED " + eventPath);
+// session.refresh(true);
+ Node node = session.getNode(eventPath);
+ Node parentNode = node.getParent();
+ if (parentNode.isNodeType(NodeType.NT_FILE)) {
if (node.isNodeType(NodeType.NT_UNSTRUCTURED)) {
if (!node.isNodeType(NodeType.MIX_LAST_MODIFIED))
node.addMixin(NodeType.MIX_LAST_MODIFIED);
// node.setProperty(JCR_ETAG, etag);
// session.save();
}
- setLastModified(node.getParent(), event);
+ setLastModified(parentNode, event);
session.save();
if (log.isTraceEnabled())
log.trace("ETag and last modified added to new " + node);
}
+
+ if (node.isNodeType(NodeType.NT_FOLDER)) {
+ setLastModified(node, event);
+ session.save();
+ if (log.isTraceEnabled())
+ log.trace("Last modified added to new " + node);
+ }
} else if (event.getType() == Event.PROPERTY_CHANGED) {
- if (!session.propertyExists(event.getPath()))
- return;
- session.refresh(true);
- Property property = session.getProperty(event.getPath());
- String propertyName = property.getName();
+ String propertyName = extractItemName(eventPath);
// skip if last modified properties are explicitly set
if (propertyName.equals(JCR_LAST_MODIFIED))
return;
if (propertyName.equals(JCR_LAST_MODIFIED_BY))
return;
+ if (propertyName.equals(JCR_MIXIN_TYPES))
+ return;
+ if (propertyName.equals(JCR_ETAG))
+ return;
+
+ if (log.isTraceEnabled())
+ log.trace("PROPERTY_CHANGED " + eventPath);
+
+ if (!session.propertyExists(eventPath))
+ return;
+// session.refresh(true);
+ Property property = session.getProperty(eventPath);
Node node = property.getParent();
if (property.getType() == PropertyType.BINARY && propertyName.equals(JCR_DATA)
&& node.isNodeType(NodeType.NT_UNSTRUCTURED)) {
if (log.isTraceEnabled())
log.trace("ETag and last modified updated for " + node);
} else if (event.getType() == Event.NODE_REMOVED) {
- String removeNodePath = event.getPath();
+ String removeNodePath = eventPath;
+ String nodeName = extractItemName(eventPath);
+ if (JCR_CONTENT.equals(nodeName)) // parent is a file, deleted anyhow
+ return;
+ if (log.isTraceEnabled())
+ log.trace("NODE_REMOVED " + eventPath);
String parentPath = JcrUtils.parentPath(removeNodePath);
- session.refresh(true);
- setLastModified(parentPath, event);
- session.save();
+// session.refresh(true);
+// setLastModified(parentPath, event);
+// session.save();
if (log.isTraceEnabled())
log.trace("Last modified updated for parents of removed " + removeNodePath);
}
}
+ private String extractItemName(String path) {
+ if (path == null || path.length() <= 1)
+ return null;
+ int lastIndex = path.lastIndexOf('/');
+ if (lastIndex >= 0) {
+ return path.substring(lastIndex + 1);
+ } else {
+ return path;
+ }
+ }
+
@Override
public void onEvent(EventIterator events) {
Runnable toRun = new Runnable() {
/** Recursively set the last updated time on parents. */
protected synchronized void setLastModified(Node node, Event event) throws RepositoryException {
if (versionManager.isCheckedOut(node.getPath())) {
- GregorianCalendar calendar = new GregorianCalendar();
- calendar.setTimeInMillis(event.getDate());
if (node.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTimeInMillis(event.getDate());
node.setProperty(Property.JCR_LAST_MODIFIED, calendar);
node.setProperty(Property.JCR_LAST_MODIFIED_BY, event.getUserID());
+ if (log.isTraceEnabled())
+ log.trace("Last modified set on " + node);
}
if (node.isNodeType(NodeType.NT_FOLDER) && !node.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
node.addMixin(NodeType.MIX_LAST_MODIFIED);
+ if (log.isTraceEnabled())
+ log.trace("Last modified mix-in added to " + node);
}
- try {
- node.getSession().save();
- } catch (RepositoryException e) {
- // fail silently and keep recursing
- }
}
- if (node.getDepth() == 0)
+
+ // end condition
+ if (node.getDepth() == 0) {
+// try {
+// node.getSession().save();
+// } catch (RepositoryException e) {
+// log.warn("Cannot index workspace", e);
+// }
return;
- Node parent = node.getParent();
- setLastModified(parent, event);
+ } else {
+ Node parent = node.getParent();
+ setLastModified(parent, event);
+ }
}
/**
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.core.RepositoryImpl;
import org.argeo.jcr.JcrUtils;
+import org.argeo.node.NodeConstants;
class JackrabbitLocalRepository extends LocalRepository {
private final static Log log = LogFactory.getLog(JackrabbitLocalRepository.class);
super(repository, cn);
Session session = KernelUtils.openAdminSession(repository);
try {
- for (String workspaceName : session.getWorkspace().getAccessibleWorkspaceNames()) {
- addMonitor(workspaceName);
- }
+ if (NodeConstants.NODE.equals(cn))
+ for (String workspaceName : session.getWorkspace().getAccessibleWorkspaceNames()) {
+ addMonitor(workspaceName);
+ }
} catch (RepositoryException e) {
throw new IllegalStateException(e);
} finally {
private void addMonitor(String realWorkspaceName) {
if (realWorkspaceName.equals(SECURITY_WORKSPACE))
return;
+ if (!NodeConstants.NODE.equals(getCn()))
+ return;
+
if (!workspaceMonitors.containsKey(realWorkspaceName)) {
try {
CmsWorkspaceIndexer workspaceMonitor = new CmsWorkspaceIndexer(
import org.argeo.jcr.JcrUtils;
+/** A read/write {@link SeekableByteChannel} based on a {@link Binary}. */
public class BinaryChannel implements SeekableByteChannel {
private final Node file;
private Binary binary;
public BinaryChannel(Node file, Path path) throws RepositoryException, IOException {
this.file = file;
- if (file.isNodeType(NodeType.NT_FILE)) {
- if (file.hasNode(Property.JCR_CONTENT)) {
- Node data = file.getNode(Property.JCR_CONTENT);
- this.binary = data.getProperty(Property.JCR_DATA).getBinary();
- } else {
- Node data = file.addNode(Property.JCR_CONTENT, NodeType.NT_UNSTRUCTURED);
- try (InputStream in = new ByteArrayInputStream(new byte[0])) {
- this.binary = data.getSession().getValueFactory().createBinary(in);
+ Session session = file.getSession();
+ synchronized (session) {
+ if (file.isNodeType(NodeType.NT_FILE)) {
+ if (file.hasNode(Node.JCR_CONTENT)) {
+ Node data = file.getNode(Property.JCR_CONTENT);
+ this.binary = data.getProperty(Property.JCR_DATA).getBinary();
+ } else {
+ Node data = file.addNode(Node.JCR_CONTENT, NodeType.NT_UNSTRUCTURED);
+ data.addMixin(NodeType.MIX_LAST_MODIFIED);
+ try (InputStream in = new ByteArrayInputStream(new byte[0])) {
+ this.binary = data.getSession().getValueFactory().createBinary(in);
+ }
+ data.setProperty(Property.JCR_DATA, this.binary);
+
+ // MIME type
+ String mime = Files.probeContentType(path);
+ // String mime = fileTypeMap.getContentType(file.getName());
+ data.setProperty(Property.JCR_MIMETYPE, mime);
+
+ session.refresh(true);
+ session.save();
+ session.notifyAll();
}
- data.setProperty(Property.JCR_DATA, this.binary);
-
- // MIME type
- String mime = Files.probeContentType(path);
- // String mime = fileTypeMap.getContentType(file.getName());
- data.setProperty(Property.JCR_MIMETYPE, mime);
-
- data.getSession().save();
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported file node " + file + " (" + file.getPrimaryNodeType() + ")");
}
- } else {
- throw new IllegalArgumentException(
- "Unsupported file node " + file + " (" + file.getPrimaryNodeType() + ")");
}
}
Binary newBinary = null;
try {
Session session = file.getSession();
- fc.position(0);
- InputStream in = Channels.newInputStream(fc);
- newBinary = session.getValueFactory().createBinary(in);
- file.getNode(Property.JCR_CONTENT).setProperty(Property.JCR_DATA, newBinary);
- session.save();
- open = false;
+ synchronized (session) {
+ fc.position(0);
+ InputStream in = Channels.newInputStream(fc);
+ newBinary = session.getValueFactory().createBinary(in);
+ file.getNode(Property.JCR_CONTENT).setProperty(Property.JCR_DATA, newBinary);
+ session.refresh(true);
+ session.save();
+ open = false;
+ session.notifyAll();
+ }
} catch (RepositoryException e) {
throw new IOException("Cannot close " + file, e);
} finally {
import org.argeo.jcr.JcrUtils;
+/** Operations on a {@link JcrFileSystem}. */
public abstract class JcrFileSystemProvider extends FileSystemProvider {
@Override
fileName = Text.escapeIllegalJcrChars(fileName);
node = parent.addNode(fileName, NodeType.NT_FILE);
node.addMixin(NodeType.MIX_CREATED);
- node.addMixin(NodeType.MIX_LAST_MODIFIED);
+// node.addMixin(NodeType.MIX_LAST_MODIFIED);
}
if (!node.isNodeType(NodeType.NT_FILE))
throw new UnsupportedOperationException(node + " must be a file");
Node parent = toNode(dir.getParent());
if (parent == null)
throw new IOException("Parent of " + dir + " does not exist");
- if (parent.getPrimaryNodeType().isNodeType(NodeType.NT_FILE)
- || parent.getPrimaryNodeType().isNodeType(NodeType.NT_LINKED_FILE))
- throw new IOException(dir + " parent is a file");
- String fileName = dir.getFileName().toString();
- fileName = Text.escapeIllegalJcrChars(fileName);
- node = parent.addNode(fileName, NodeType.NT_FOLDER);
- node.addMixin(NodeType.MIX_CREATED);
- node.addMixin(NodeType.MIX_LAST_MODIFIED);
- node.getSession().save();
+ Session session = parent.getSession();
+ synchronized (session) {
+ if (parent.getPrimaryNodeType().isNodeType(NodeType.NT_FILE)
+ || parent.getPrimaryNodeType().isNodeType(NodeType.NT_LINKED_FILE))
+ throw new IOException(dir + " parent is a file");
+ String fileName = dir.getFileName().toString();
+ fileName = Text.escapeIllegalJcrChars(fileName);
+ node = parent.addNode(fileName, NodeType.NT_FOLDER);
+ node.addMixin(NodeType.MIX_CREATED);
+ node.addMixin(NodeType.MIX_LAST_MODIFIED);
+ save(session);
+ }
} else {
// if (!node.getPrimaryNodeType().isNodeType(NodeType.NT_FOLDER))
// throw new FileExistsException(dir + " exists and is not a directory");
if (node == null)
throw new NoSuchFileException(path + " does not exist");
Session session = node.getSession();
- if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FILE))
- node.remove();
- else if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FOLDER)) {
- if (node.hasNodes())// TODO check only files
- throw new DirectoryNotEmptyException(path.toString());
- node.remove();
+ synchronized (session) {
+ session.refresh(false);
+ if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FILE))
+ node.remove();
+ else if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FOLDER)) {
+ if (node.hasNodes())// TODO check only files
+ throw new DirectoryNotEmptyException(path.toString());
+ node.remove();
+ }
+ save(session);
}
- session.save();
} catch (RepositoryException e) {
discardChanges(node);
throw new IOException("Cannot delete " + path, e);
Node sourceNode = toNode(source);
Node targetNode = toNode(target);
try {
- JcrUtils.copy(sourceNode, targetNode);
- sourceNode.getSession().save();
+ Session targetSession = targetNode.getSession();
+ synchronized (targetSession) {
+ JcrUtils.copy(sourceNode, targetNode);
+ save(targetSession);
+ }
} catch (RepositoryException e) {
discardChanges(sourceNode);
discardChanges(targetNode);
Node sourceNode = toNode(source);
try {
Session session = sourceNode.getSession();
- session.move(sourceNode.getPath(), target.toString());
- session.save();
+ synchronized (session) {
+ session.move(sourceNode.getPath(), target.toString());
+ save(session);
+ }
} catch (RepositoryException e) {
discardChanges(sourceNode);
throw new IOException("Cannot move from " + source + " to " + target, e);
public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {
Node node = toNode(path);
try {
- if (value instanceof byte[]) {
- JcrUtils.setBinaryAsBytes(node, attribute, (byte[]) value);
- } else if (value instanceof Calendar) {
- node.setProperty(attribute, (Calendar) value);
- } else {
- node.setProperty(attribute, value.toString());
+ Session session = node.getSession();
+ synchronized (session) {
+ if (value instanceof byte[]) {
+ JcrUtils.setBinaryAsBytes(node, attribute, (byte[]) value);
+ } else if (value instanceof Calendar) {
+ node.setProperty(attribute, (Calendar) value);
+ } else {
+ node.setProperty(attribute, value.toString());
+ }
+ save(session);
}
- node.getSession().save();
} catch (RepositoryException e) {
discardChanges(node);
throw new IOException("Cannot set attribute " + attribute + " on " + path, e);
}
}
+ /** Make sure save is robust. */
+ protected void save(Session session) throws RepositoryException {
+ session.refresh(true);
+ session.save();
+ session.notifyAll();
+ }
+
/**
* To be overriden in order to support the ~ path, with an implementation
* specific concept of user home.
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+/** A {@link Path} which contains a reference to a JCR {@link Node}. */
public class JcrPath implements Path {
private final static String delimStr = "/";
private final static char delimChar = '/';