You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2008/07/28 17:54:15 UTC
svn commit: r680383 - in /incubator/sling/whiteboard/jcrbundles: ./
src/main/java/org/apache/sling/jcr/jcrbundles/
Author: bdelacretaz
Date: Mon Jul 28 08:54:12 2008
New Revision: 680383
URL: http://svn.apache.org/viewvc?rev=680383&view=rev
Log:
SLING-587 - work in progress, simple bundles folders watching implemented
Added:
incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundlesFolder.java (with props)
incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/NodeProcessor.java (with props)
Modified:
incubator/sling/whiteboard/jcrbundles/pom.xml
incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java
Modified: incubator/sling/whiteboard/jcrbundles/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/jcrbundles/pom.xml?rev=680383&r1=680382&r2=680383&view=diff
==============================================================================
--- incubator/sling/whiteboard/jcrbundles/pom.xml (original)
+++ incubator/sling/whiteboard/jcrbundles/pom.xml Mon Jul 28 08:54:12 2008
@@ -72,6 +72,11 @@
<artifactId>org.osgi.compendium</artifactId>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.api</artifactId>
+ <version>2.0.2-incubator</version>
+ </dependency>
+ <dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
Added: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundlesFolder.java
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundlesFolder.java?rev=680383&view=auto
==============================================================================
--- incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundlesFolder.java (added)
+++ incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundlesFolder.java Mon Jul 28 08:54:12 2008
@@ -0,0 +1,207 @@
+/*
+ * 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.apache.sling.jcr.jcrbundles;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+
+import org.apache.sling.jcr.api.SlingRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Manages a folder that contains bundles and configurations: listens to
+ * changes in the folder, and rescan it when needed, passing nodes to
+ * NodeProcessors that want to process them.
+ */
+class BundlesFolder implements EventListener {
+ protected static final Logger log = LoggerFactory.getLogger(BundlesFolder.class);
+
+ private final String path;
+ private final Session session;
+ private long nextScan;
+
+ /** After receiving JCR events, we wait for this many msec before
+ * re-scanning the folder, as events often come in bursts.
+ */
+ public static final long SCAN_DELAY_MSEC = 1000;
+
+ /** List of processors for our bundles and configs */
+ private final List<NodeProcessor> processors;
+
+ /** Only folders having this name can contain bundles and configs */
+ public static final String BUNDLES_NODENAME = "bundles";
+
+ /** Only folders having this type can contain bundles and configs */
+ public static final String BUNDLES_NODETYPE = "nt:hierarchyNode";
+
+ /** Create a BundlesFolder on the given Repository, at the
+ * given path
+ */
+ BundlesFolder(SlingRepository r, String path, List<NodeProcessor> processors) throws RepositoryException {
+ this.path = path;
+ this.processors = processors;
+ session = r.loginAdministrative(r.getDefaultWorkspace());
+
+ // observe any changes in our folder, recursively
+ final int eventTypes = Event.NODE_ADDED | Event.NODE_REMOVED
+ | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
+ final boolean isDeep = true;
+ final boolean noLocal = true;
+ session.getWorkspace().getObservationManager().addEventListener(this, eventTypes, path,
+ isDeep, null, null, noLocal);
+
+ // trigger the initial scan without waiting
+ setScanTimer(0);
+
+ log.info("{} created for path {}", getClass().getSimpleName(), path);
+ }
+
+ /** MUST be called when done using this object */
+ void cleanup() throws RepositoryException {
+ session.getWorkspace().getObservationManager().removeEventListener(this);
+ session.logout();
+ }
+
+ /** Any event causes us to rescan our folder, once there are no more
+ * events during SCAN_DELAY_MSEC
+ */
+ public void onEvent(EventIterator it) {
+ setScanTimer(SCAN_DELAY_MSEC);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if( !(obj instanceof BundlesFolder) ) {
+ return false;
+ }
+
+ final BundlesFolder other = (BundlesFolder)obj;
+ return path.equals(other.path);
+ }
+
+ @Override
+ public int hashCode() {
+ return path.hashCode();
+ }
+
+ /** Find all bundles folders under rootPath */
+ static Set<BundlesFolder> findBundlesFolders(SlingRepository r, String rootPath,
+ List<NodeProcessor> processors)
+ throws RepositoryException {
+ final Set<BundlesFolder> result = new HashSet<BundlesFolder>();
+ Session s = null;
+
+ try {
+ s = r.loginAdministrative(r.getDefaultWorkspace());
+ if(!s.getRootNode().hasNode(relPath(rootPath))) {
+ log.info("Bundles root node {} not found, ignored", rootPath);
+ } else {
+ log.debug("Bundles root node {} found, looking for bundle folders inside it", rootPath);
+ final Node n = s.getRootNode().getNode(relPath(rootPath));
+ findBundlesFolders(r, n, result, processors);
+ }
+ } finally {
+ if(s != null) {
+ s.logout();
+ }
+ }
+
+ return result;
+ }
+
+ /** Add n to setToUpdate if it is a bundle folder, and recurse into its children
+ * to do the same.
+ */
+ static void findBundlesFolders(SlingRepository r, Node n,
+ Set<BundlesFolder> setToUpdate, List<NodeProcessor> processors)
+ throws RepositoryException {
+ if(n.getName().equals(BUNDLES_NODENAME)) {
+ /*
+ if(!n.isNodeType(BUNDLES_NODETYPE)) {
+ log.debug("{} node does not have {} type, ignored", n.getPath(), BUNDLES_NODETYPE);
+ }*/
+ setToUpdate.add(new BundlesFolder(r, n.getPath(), processors));
+ }
+ final NodeIterator it = n.getNodes();
+ while(it.hasNext()) {
+ findBundlesFolders(r, it.nextNode(), setToUpdate, processors);
+ }
+
+ }
+
+ /** Set or reset our scanning timer: scanIfNeeded() will do nothing
+ * unless this timer has expired */
+ protected void setScanTimer(long delayMsec) {
+ nextScan = System.currentTimeMillis() + delayMsec;
+ }
+
+ /** If our timer allows it, recursively call processNode
+ * on our Node and its children */
+ void scanIfNeeded() throws RepositoryException {
+ if(nextScan != -1 && System.currentTimeMillis() > nextScan) {
+ nextScan = -1;
+ log.debug("Timer expired, scanning {}", path);
+
+ // TODO handle case where folder disappears
+ final Node n = session.getRootNode().getNode(relPath(path));
+ processNode(n);
+ }
+ }
+
+ /** Install/update/remove the bundle or config that Node n
+ * represents, if any. */
+ protected void processNode(Node n) throws RepositoryException {
+
+ boolean accepted = false;
+
+ for(NodeProcessor p : processors) {
+ if(p.accepts(n)) {
+ accepted = true;
+ p.process(n);
+ break;
+ }
+ }
+
+ if(!accepted) {
+ log.debug("No NodeProcessor found for node {}, ignored", n.getPath());
+ }
+
+ final NodeIterator it = n.getNodes();
+ while(it.hasNext()) {
+ processNode(it.nextNode());
+ }
+ }
+
+ static String relPath(String path) {
+ if(path.startsWith("/")) {
+ return path.substring(1);
+ }
+ return path;
+ }
+
+}
\ No newline at end of file
Propchange: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundlesFolder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/BundlesFolder.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
Modified: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java?rev=680383&r1=680382&r2=680383&view=diff
==============================================================================
--- incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java (original)
+++ incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/JcrBundlesManager.java Mon Jul 28 08:54:12 2008
@@ -18,5 +18,134 @@
*/
package org.apache.sling.jcr.jcrbundles;
-public class JcrBundlesManager {
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** JcrBundlesManager service, manages OSGi bundles and
+ * configurations stored in the JCR Repository.
+ *
+ * @scr.service
+ *
+ * @scr.component
+ * immediate="true"
+ * metatype="no"
+ *
+ * @scr.property
+ * name="service.description"
+ * value="Sling JCR Bundles Manager Service"
+ *
+ * @scr.property
+ * name="service.vendor"
+ * value="The Apache Software Foundation"
+ */
+
+public class JcrBundlesManager implements Runnable {
+ /** Ordered list of root paths to observe for bundles and configs
+ * TODO should be configurable
+ */
+ private String [] bundleRoots = { "/libs", "/apps" };
+
+ /** List of processors for our bundles and configs */
+ private List<NodeProcessor> processors;
+
+ /** Set of BundleFolders that we manage */
+ private Set<BundlesFolder> folders;
+
+ /** @scr.reference */
+ private SlingRepository repository;
+
+ /** Default log. */
+ protected final Logger log = LoggerFactory.getLogger(this.getClass());
+
+ /** When activated, collect the list of bundle folders to scan
+ * and register as a listener for future updates.
+ */
+ protected void activate(ComponentContext context) throws RepositoryException {
+
+ // setup our processors
+ processors = new LinkedList<NodeProcessor>();
+ processors.add(new NodeProcessor() {
+ public boolean accepts(Node n) throws RepositoryException {
+ return true;
+ }
+
+ public void process(Node n) throws RepositoryException {
+ log.debug("Dummy NodeProcessor would process Node {}", n.getPath());
+ }
+
+ });
+
+ // find "bundles" folders and add them to processing queue
+ folders = new HashSet<BundlesFolder>();
+ for(String rootPath : bundleRoots) {
+ folders.addAll(BundlesFolder.findBundlesFolders(repository, rootPath, processors));
+ }
+
+ // TODO: should listen for any new "bundles" folders created after activation
+
+ // start queue processing
+ final Thread t = new Thread(this, getClass().getSimpleName());
+ t.setDaemon(true);
+ t.start();
+ }
+
+ /** Cleanup */
+ protected void deactivate(ComponentContext oldContext) {
+ for(BundlesFolder bf : folders) {
+ try {
+ bf.cleanup();
+ } catch(RepositoryException e) {
+ log.warn("RepositoryException in deactivate", e);
+ }
+ }
+
+ folders.clear();
+ }
+
+ /** Scan paths once their timer expires */
+ public void run() {
+ Session s = null;
+
+ // We could use the scheduler service but that makes things harder to test
+ while(true) {
+ try {
+ s = repository.loginAdministrative(repository.getDefaultWorkspace());
+ runOneCycle(s);
+ } catch(IllegalArgumentException ie) {
+ log.warn("IllegalArgumentException in " + getClass().getSimpleName(), ie);
+ } catch(RepositoryException re) {
+ log.warn("RepositoryException in " + getClass().getSimpleName(), re);
+
+ } finally {
+ if(s!= null) {
+ s.logout();
+ s = null;
+ }
+ try {
+ Thread.sleep(1000L);
+ } catch(InterruptedException ignore) {
+ // ignore
+ }
+ }
+ }
+
+ }
+
+ /** Run one cycle of processing our scanTimes queue */
+ void runOneCycle(Session s) throws RepositoryException {
+ for(BundlesFolder bf : folders) {
+ bf.scanIfNeeded();
+ }
+ }
}
\ No newline at end of file
Added: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/NodeProcessor.java
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/NodeProcessor.java?rev=680383&view=auto
==============================================================================
--- incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/NodeProcessor.java (added)
+++ incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/NodeProcessor.java Mon Jul 28 08:54:12 2008
@@ -0,0 +1,11 @@
+package org.apache.sling.jcr.jcrbundles;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/** Interface for accepting and processing Nodes */
+
+interface NodeProcessor {
+ boolean accepts(Node n) throws RepositoryException;
+ void process(Node n) throws RepositoryException;
+}
Propchange: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/NodeProcessor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/sling/whiteboard/jcrbundles/src/main/java/org/apache/sling/jcr/jcrbundles/NodeProcessor.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL