From: <mol...@us...> - 2008-04-29 12:53:49
|
Revision: 805 http://openutils.svn.sourceforge.net/openutils/?rev=805&view=rev Author: molaschi Date: 2008-04-29 05:53:22 -0700 (Tue, 29 Apr 2008) Log Message: ----------- Add openutils-mgnlbootstrapsync files Added Paths: ----------- trunk/openutils-mgnlbootstrapsync/pom.xml trunk/openutils-mgnlbootstrapsync/src/ trunk/openutils-mgnlbootstrapsync/src/main/ trunk/openutils-mgnlbootstrapsync/src/main/java/ trunk/openutils-mgnlbootstrapsync/src/main/java/it/ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapAtomicFilter.java trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapEnableRoot.java trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapExportRoot.java trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/lifecycle/ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/lifecycle/BootstrapSyncModuleLifecycle.java trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/AbstractBootstrapSyncListener.java trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/BootstrapSyncListener.java trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/watch/ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/watch/BootstrapSyncRepositoryWatch.java trunk/openutils-mgnlbootstrapsync/src/main/resources/ trunk/openutils-mgnlbootstrapsync/src/main/resources/META-INF/ trunk/openutils-mgnlbootstrapsync/src/main/resources/META-INF/magnolia/ trunk/openutils-mgnlbootstrapsync/src/main/resources/META-INF/magnolia/bootstrapsync.xml Added: trunk/openutils-mgnlbootstrapsync/pom.xml =================================================================== --- trunk/openutils-mgnlbootstrapsync/pom.xml (rev 0) +++ trunk/openutils-mgnlbootstrapsync/pom.xml 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>net.sourceforge.openutils</groupId> + <artifactId>openutils</artifactId> + <version>8</version> + <relativePath>..</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <packaging>jar</packaging> + <artifactId>openutils-mgnlbootstrapsync</artifactId> + <name>openutils-mgnlbootstrapsync</name> + <version>0.1-SNAPSHOT</version> + <licenses> + <license> + <name>GPLv3</name> + <url>http://www.gnu.org/licenses/gpl-3.0.txt</url> + </license> + </licenses> + <build> + <resources> + <resource> + <filtering>false</filtering> + <directory>src/main/resources</directory> + <includes> + <include>**/*</include> + </includes> + </resource> + <resource> + <filtering>true</filtering> + <directory>src/main/resources</directory> + <includes> + <include>META-INF/magnolia/*</include> + </includes> + </resource> + </resources> + </build> + <dependencies> + <dependency> + <groupId>info.magnolia</groupId> + <artifactId>magnolia-core</artifactId> + <version>3.5-rc2</version> + </dependency> + <dependency> + <groupId>info.magnolia</groupId> + <artifactId>magnolia-module-admininterface</artifactId> + <version>3.5.2</version> + </dependency> + <dependency> + <groupId>org.testng</groupId> + <artifactId>testng</artifactId> + <classifier>jdk15</classifier> + <version>5.1</version> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + <repositories> + <repository> + <id>repository.magnolia.info</id> + <name>magnolia repository</name> + <url>http://svn.magnolia.info/maven/m2</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </repository> + </repositories> +</project> Property changes on: trunk/openutils-mgnlbootstrapsync/pom.xml ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapAtomicFilter.java =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapAtomicFilter.java (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapAtomicFilter.java 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,144 @@ +package it.openutils.mgnlbootstrapsync; + +import info.magnolia.cms.core.ie.filters.VersionFilter; + +import org.apache.commons.lang.ArrayUtils; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLFilterImpl; + + +/** + * @author mmolaschi + * @version $Id: $ + */ +public class BootstrapAtomicFilter extends XMLFilterImpl +{ + + private int inLevel; + + private int inVersionElement; + + private boolean inMetadata; + + /** + * @param parent parent reader + */ + public BootstrapAtomicFilter(XMLReader parent) + { + super(parent); + } + + /** + * {@inheritDoc} + */ + @Override + public void endElement(String uri, String localName, String qName) throws SAXException + { + if (inVersionElement > 0) + { + inVersionElement--; + return; + } + + if (inLevel > 0) + { + if ("sv:node".equals(qName)) + { + if (inMetadata && inLevel == 3) + { + inMetadata = false; + inLevel--; + super.endElement(uri, localName, qName); + return; + } + inLevel--; + + if (inLevel > 1) + { + return; + } + } + if (inMetadata && inLevel >= 2) + { + super.endElement(uri, localName, qName); + return; + } + if (inLevel > 2) + { + return; + } + } + + super.endElement(uri, localName, qName); + } + + /** + * {@inheritDoc} + */ + @Override + public void characters(char[] ch, int start, int length) throws SAXException + { + // filter content + if (inVersionElement == 0 && (inMetadata || inLevel <= 2)) + { + super.characters(ch, start, length); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException + { + if (inVersionElement > 0) + { + inVersionElement++; + return; + } + if ("sv:node".equals(qName)) + { + String attName = atts.getValue("sv:name"); //$NON-NLS-1$ + if (attName != null && ArrayUtils.contains(VersionFilter.FILTERED_NODES, attName)) + { + inVersionElement++; + return; + } + } + else if ("sv:property".equals(qName)) + { + String attName = atts.getValue("sv:name"); //$NON-NLS-1$ + if (attName != null && ArrayUtils.contains(VersionFilter.FILTERED_PROPERTIES, attName)) + { + inVersionElement++; + return; + } + } + + if (!inMetadata && inLevel > 2) + { + if ("sv:node".equals(qName)) + { + inLevel++; + } + return; + } + + if ("sv:node".equals(qName)) + { + String attName = atts.getValue("sv:name"); + inLevel++; + if ("MetaData".equals(attName) && inLevel == 3) + { + inMetadata = true; + } + else if (inLevel > 2) + { + return; + } + } + super.startElement(uri, localName, qName, atts); + } +} Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapAtomicFilter.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapEnableRoot.java =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapEnableRoot.java (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapEnableRoot.java 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,125 @@ +package it.openutils.mgnlbootstrapsync; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; + + +/** + * @author mmolaschi luca boati + * @version $Id: $ + */ +public class BootstrapEnableRoot +{ + + private String enableRoots; + + private List<String[]> rootTokensList; + + /** + * + */ + public BootstrapEnableRoot() + { + + } + + /** + * + * @param enableRoots comma separeted list of enabled roots + */ + public BootstrapEnableRoot(String enableRoots) + { + this.setEnableRoots(enableRoots); + } + + /** + * Returns the enableRoots. + * @return the enableRoots + */ + public String getEnableRoots() + { + return enableRoots; + } + + /** + * Sets the enableRoots. + * @param enableRoots the enableRoots to set + */ + public void setEnableRoots(String enableRoots) + { + this.enableRoots = enableRoots; + + if (enableRoots != null) + { + String[] roots = StringUtils.split(enableRoots, ","); + rootTokensList = new ArrayList<String[]>(roots.length); + for (String root : roots) + { + String[] rootTokens = StringUtils.split(root, "/"); + int i = 0; + for (String[] rt : rootTokensList) + { + if (rootTokens.length > rt.length) + { + rootTokensList.add(i, rootTokens); + i = -1; + break; + } + i++; + } + if (i >= 0) + { + rootTokensList.add(rootTokens); + } + } + } + } + + /** + * Check if a path is enabled + * @param path path to check + * @return true if path is enabled + */ + public boolean isEnable(String path) + { + // check if a node can be exported + if (path == null) + { + return true; + } + + // if enablePath is not set, the node can be exported + if (rootTokensList == null || rootTokensList.size() == 0) + { + return true; + } + + String[] pathTokens = StringUtils.split(path, "/"); + for (String[] rootTokens : rootTokensList) + { + if (pathTokens.length < rootTokens.length) + { + continue; + } + boolean match = true; + for (int i = 0; i < rootTokens.length; i++) + { + if (!rootTokens[i].equals(pathTokens[i])) + { + match = false; + break; + } + } + + if (match) + { + return true; + } + } + + return false; + + } +} Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapEnableRoot.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapExportRoot.java =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapExportRoot.java (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapExportRoot.java 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,137 @@ +package it.openutils.mgnlbootstrapsync; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; + + +/** + * @author mmolaschi luca boati + * @version $Id: $ + */ +public class BootstrapExportRoot +{ + + private String exportRoots; + + private List<String[]> rootTokensList; + + /** + * + */ + public BootstrapExportRoot() + { + + } + + /** + * @param exportRoots comma separeted list of nodes (every modified to children will be exported as this node) + */ + public BootstrapExportRoot(String exportRoots) + { + this.setExportRoots(exportRoots); + } + + /** + * Returns the exportRoots. + * @return the exportRoots + */ + public String getExportRoots() + { + return exportRoots; + } + + /** + * Sets the exportRoots. + * @param exportRoots the exportRoots to set + */ + public void setExportRoots(String exportRoots) + { + this.exportRoots = exportRoots; + + if (exportRoots != null) + { + String[] roots = StringUtils.split(exportRoots, ","); + rootTokensList = new ArrayList<String[]>(roots.length); + for (String root : roots) + { + String[] rootTokens = StringUtils.split(root, "/"); + int i = 0; + for (String[] rt : rootTokensList) + { + if (rootTokens.length > rt.length) + { + rootTokensList.add(i, rootTokens); + i = -1; + break; + } + i++; + } + if (i >= 0) + { + rootTokensList.add(rootTokens); + } + } + } + } + + /** + * Check if path match some root node + * @param path path to check + * @return true if a path match some root + */ + public boolean match(String path) + { + return null != getRootPath(path); + } + + /** + * Get matching root for path + * @param path path + * @return matching root + */ + public String getRootPath(String path) + { + if (rootTokensList == null || rootTokensList.size() == 0) + { + return null; + } + + String[] pathTokens = StringUtils.split(path, "/"); + for (String[] rootTokens : rootTokensList) + { + if (pathTokens.length < rootTokens.length) + { + continue; + } + boolean match = true; + for (int i = 0; i < rootTokens.length; i++) + { + if (rootTokens[i].equals("*")) + { + continue; + } + if (!rootTokens[i].equals(pathTokens[i])) + { + match = false; + break; + } + } + if (match) + { + String[] pathRootTokens = (String[]) ArrayUtils.subarray(pathTokens, 0, rootTokens.length); + + String pathRoot = StringUtils.join(pathRootTokens, "/"); + if (!pathRoot.startsWith("/")) + { + pathRoot = "/" + pathRoot; + } + return pathRoot; + } + } + return null; + + } +} Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/BootstrapExportRoot.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/lifecycle/BootstrapSyncModuleLifecycle.java =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/lifecycle/BootstrapSyncModuleLifecycle.java (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/lifecycle/BootstrapSyncModuleLifecycle.java 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,143 @@ +package it.openutils.mgnlbootstrapsync.lifecycle; + +import java.util.HashMap; +import java.util.Map; + +import javax.jcr.RepositoryException; +import javax.jcr.observation.Event; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.magnolia.cms.core.HierarchyManager; +import info.magnolia.cms.core.ItemType; +import info.magnolia.cms.core.SystemProperty; +import info.magnolia.context.MgnlContext; +import info.magnolia.module.ModuleLifecycle; +import info.magnolia.module.ModuleLifecycleContext; +import it.openutils.mgnlbootstrapsync.listener.AbstractBootstrapSyncListener; +import it.openutils.mgnlbootstrapsync.listener.BootstrapSyncListener; +import it.openutils.mgnlbootstrapsync.watch.BootstrapSyncRepositoryWatch; + + +/** + * @author molaschi + * @version $Id: $ + */ +public class BootstrapSyncModuleLifecycle implements ModuleLifecycle +{ + + /** + * Logger. + */ + private Logger log = LoggerFactory.getLogger(BootstrapSyncModuleLifecycle.class); + + private Map<String, AbstractBootstrapSyncListener> listeners = new HashMap<String, AbstractBootstrapSyncListener>(); + + /** + * {@inheritDoc} + */ + public void start(ModuleLifecycleContext moduleLifecycleContext) + { + // is develop? + boolean develop = SystemProperty.getBooleanProperty("magnolia.develop"); + // bootstrap sync enabled? + boolean bootstrapSync = SystemProperty.getBooleanProperty("magnolia.bootstrapSync"); + + if (develop && bootstrapSync) + { + // get all repositories on which activate bootstrap sync + String[] repositories = StringUtils.split( + SystemProperty.getProperty("magnolia.bootstrapSync.repositories"), + ","); + + // cycle + for (String repository : repositories) + { + // get synchronization property for each repository + + // get path to export to + String exportPath = SystemProperty.getProperty("magnolia.bootstrapSync." + repository + ".exportPath"); + + // get roots to export (node with all children) + String exportRoots = SystemProperty + .getProperty("magnolia.bootstrapSync." + repository + ".exportRoots"); + + // get roots from which to export (one file for each node (ordering problem)) + String enableRoots = SystemProperty + .getProperty("magnolia.bootstrapSync." + repository + ".enablePaths"); + + // get node type to export + String nodeType = SystemProperty + .getProperty("magnolia.bootstrapSync." + repository + ".nodeType"); + if (nodeType == null) + { + nodeType = ItemType.CONTENT.getSystemName(); + } + + // create watch + BootstrapSyncRepositoryWatch watch = new BootstrapSyncRepositoryWatch( + repository, + exportPath, + exportRoots, + enableRoots, + nodeType); + + // create listener + BootstrapSyncListener listener = new BootstrapSyncListener(watch); + + try + { + HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(repository); + + log.debug("Starting listener on repository {}", repository); + hm.getWorkspace().getObservationManager().addEventListener( + listener, + Event.NODE_ADDED + | Event.PROPERTY_CHANGED + | Event.PROPERTY_ADDED + | Event.PROPERTY_REMOVED + | Event.NODE_REMOVED, + "/", + true, + null, + null, + false); + + // store + listeners.put(watch.getRepository(), listener); + } + catch (RepositoryException ex) + { + log.error(ex.getMessage(), ex); + log.error("Stopping BootstrapSync Listeners"); + stop(moduleLifecycleContext); + break; + } + } + } + } + + /** + * {@inheritDoc} + */ + public void stop(ModuleLifecycleContext moduleLifecycleContext) + { + for (Map.Entry<String, AbstractBootstrapSyncListener> entry : listeners.entrySet()) + { + HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(entry.getKey()); + try + { + // stop listener + log.debug("Stopping listener on repository {}", entry.getKey()); + hm.getWorkspace().getObservationManager().removeEventListener(entry.getValue()); + } + catch (RepositoryException ex) + { + log.error(ex.getMessage(), ex); + } + } + } + +} Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/lifecycle/BootstrapSyncModuleLifecycle.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/AbstractBootstrapSyncListener.java =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/AbstractBootstrapSyncListener.java (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/AbstractBootstrapSyncListener.java 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,427 @@ +package it.openutils.mgnlbootstrapsync.listener; + +import info.magnolia.cms.core.Content; +import info.magnolia.cms.core.HierarchyManager; +import info.magnolia.cms.core.Path; +import info.magnolia.cms.core.ie.DataTransporter; +import info.magnolia.cms.core.ie.filters.VersionFilter; +import info.magnolia.cms.security.AccessDeniedException; +import info.magnolia.cms.util.ContentUtil; +import info.magnolia.context.MgnlContext; +import it.openutils.mgnlbootstrapsync.BootstrapAtomicFilter; +import it.openutils.mgnlbootstrapsync.watch.BootstrapSyncRepositoryWatch; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.zip.DeflaterOutputStream; + +import javax.jcr.PathNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.observation.EventIterator; +import javax.jcr.observation.EventListener; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * + * @author mmolaschi + * @version $Id: $ + */ +public abstract class AbstractBootstrapSyncListener implements EventListener +{ + + private static Logger log = LoggerFactory.getLogger(AbstractBootstrapSyncListener.class); + + private BootstrapSyncRepositoryWatch watch; + + private Object synchronizationObject = new Object(); + + /** + * + * @param watch watch for this listener + */ + public AbstractBootstrapSyncListener(BootstrapSyncRepositoryWatch watch) + { + this.watch = watch; + } + + + /** + * {@inheritDoc} + */ + public abstract void onEvent(EventIterator events); + + public BootstrapSyncRepositoryWatch getWatch() + { + return watch; + } + + public void setWatch(BootstrapSyncRepositoryWatch watch) + { + this.watch = watch; + } + + /** + * Change event on node + * @param nodePath path to node + */ + public void exportNode(String nodePath) + { + synchronized (synchronizationObject) + { + String path = nodePath; + + // get repository manager + HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(watch.getRepository()); + + // check if path can exported + boolean isEnablePath = this.watch.getEnableRoots().isEnable(path); + if (isEnablePath) + { + try + { + // check if it is a property + if (hm.isNodeData(path)) + { + // move to parent node + path = StringUtils.substringBeforeLast(path, "/"); + } + } + catch (AccessDeniedException e) + { + log.error(e.getMessage(), e); + return; + } + + Content exported = null; + + try + { + // get exported content + exported = getRightContent(hm.getContent(path), watch.getNodeType()); + if (exported == null) + { + return; + } + } + catch (RepositoryException e) + { + if (log.isDebugEnabled() && e instanceof PathNotFoundException) + { + log.debug("Path already deleted:" + path); + } + if (log.isErrorEnabled() && !(e instanceof PathNotFoundException)) + { + log.error("Error hierarchy manager for path " + path, e); + } + return; + } + + // get handle + String handle = exported.getHandle(); + + // check if path is under a "compressed" node + String pathToExport = this.watch.getExportRoots().getRootPath(handle); + + if (pathToExport == null) + { + // not "compressed" + exportFileIterative(hm, exported); + } + else + { + exportFile(hm, pathToExport, false); + } + } + } + } + + /** + * Remove event on node + * @param path path to node + */ + public void removeNode(String path) + { + // synchornization + synchronized (synchronizationObject) + { + // get hierarchy manager + HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(watch.getRepository()); + + // check if path can exported + boolean isEnablePath = this.watch.getEnableRoots().isEnable(path); + if (isEnablePath) + { + // check if path is under a "compressed" node + String pathToExport = this.watch.getExportRoots().getRootPath(path); + + if (pathToExport == null || pathToExport.equals(path)) + { + // remove every file that starts with path + cleanFileSystem(path); + + try + { + // get parent node + String parentHandle = StringUtils.substringBeforeLast(path, "/"); + String parentXmlName = watch.getRepository() + + StringUtils.replace(parentHandle, "/", ".") + + ".xml"; + if (parentHandle.length() == 0) + { + parentHandle = "/"; + } + + // check if path is under a "compressed" node + String pathParentToExport = this.watch.getExportRoots().getRootPath(parentHandle); + + if (pathParentToExport == null) + { + // xml reader for filtering 2 levels + BootstrapAtomicFilter xmlReader = new BootstrapAtomicFilter(XMLReaderFactory + .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName())); + + // export parent node + exportFile(parentXmlName, xmlReader, hm, parentHandle); + } + else + { + exportFile(hm, pathParentToExport, false); + } + } + catch (SAXException ex) + { + throw new RuntimeException(ex); + } + } + else + { + exportFile(hm, pathToExport, false); + } + } + } + } + + /** + * Go up in tree until the current node type equals passed item type + * @param c current node + * @param itemType item type to check + * @return right node or null if not found + * @throws RepositoryException repository exception + */ + @SuppressWarnings("unchecked") + private Content getRightContent(Content c, String itemType) throws RepositoryException + { + if (c.getItemType().getSystemName().equals(itemType)) + { + return c; + } + if (c.getChildren() != null) + { + Iterator it = c.getChildren().iterator(); + while(it.hasNext()) + { + return getRightContent((Content)it.next(), itemType); + } + } + return null; + } + + /** + * Export node and its subnodes + * @param hm hierarchy manager + * @param node node + */ + @SuppressWarnings("unchecked") + protected void exportFileIterative(HierarchyManager hm, Content node) + { + // write itself + exportFile(hm, node.getHandle(), true); + + // cycle on children + Collection<Content> children = node.getChildren(ContentUtil.EXCLUDE_META_DATA_CONTENT_FILTER); + if (children != null) + { + for (Content child : children) + { + exportFileIterative(hm, child); + } + } + } + + /** + * Export node to file + * @param hm hierarchy manager + * @param handle path to node + * @param singleNode export single node in file + */ + protected void exportFile(HierarchyManager hm, String handle, boolean singleNode) + { + try + { + if (singleNode) + { + String parentHandle = StringUtils.substringBeforeLast(handle, "/"); + String parentXmlName = watch.getRepository() + StringUtils.replace(parentHandle, "/", ".") + ".xml"; + if (parentHandle.length() == 0) + { + parentHandle = "/"; + } + + BootstrapAtomicFilter xmlReader = new BootstrapAtomicFilter(XMLReaderFactory + .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName())); + + exportFile(parentXmlName, xmlReader, hm, parentHandle); + } + String xmlName = watch.getRepository() + StringUtils.replace(handle, "/", ".") + ".xml"; + + XMLReader xmlReader = null; + + if (singleNode) + { + xmlReader = new BootstrapAtomicFilter(XMLReaderFactory + .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName())); + } + exportFile(xmlName, xmlReader, hm, handle); + } + catch (SAXException ex) + { + throw new RuntimeException(ex); + } + } + + /** + * + * @param fileName file name + * @param reader xml filter + * @param hm hierarchy manager + * @param handle path to node + */ + protected void exportFile(String fileName, XMLReader reader, HierarchyManager hm, String handle) + { + // create necessary parent directories + File folder = new File(Path.getAbsoluteFileSystemPath(watch.getExportPath())); + folder.mkdirs(); + + File xmlFile = new File(folder.getAbsoluteFile(), fileName); + FileOutputStream fos = null; + try + { + fos = new FileOutputStream(xmlFile); + } + catch (FileNotFoundException e) + { + log.error(e.getMessage(), e); + return; + } + + try + { + executeExport(fos, reader, hm.getWorkspace().getSession(), handle, watch.getRepository()); + } + catch (IOException e) + { + log.error(e.getMessage(), e); + } + finally + { + IOUtils.closeQuietly(fos); + } + } + + /** + * Clean files for node (path) + * @param path path to node + */ + protected void cleanFileSystem(String path) + { + + String baseName = watch.getRepository() + StringUtils.replace(path, "/", "."); + + // create necessary parent directories + File folder = new File(Path.getAbsoluteFileSystemPath(watch.getExportPath())); + + if (folder.exists()) + { + String[] files = folder.list(); + for (String file : files) + { + File f = new File(folder, file); + if (f.exists() && f.getName().startsWith(baseName)) + { + f.delete(); + log.debug("Removed File: " + f.getName()); + } + } + } + } + + /** + * Execute export + * @param baseOutputStream file output stream + * @param reader xml filter + * @param session jcr session + * @param basepath path to node + * @param repository repository + * @throws IOException exception writing file + */ + protected static void executeExport(OutputStream baseOutputStream, XMLReader reader, Session session, + String basepath, String repository) throws IOException + { + OutputStream outputStream = baseOutputStream; + + try + { + // use XMLSerializer and a SAXFilter in order to rewrite the + // file + + XMLReader xmlReader = reader; + if (reader == null) + { + xmlReader = new VersionFilter(XMLReaderFactory + .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName())); + } + else + { + xmlReader = new VersionFilter(reader); + } + + DataTransporter.parseAndFormat(outputStream, xmlReader, repository, basepath, session, false); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + catch (SAXException e) + { + throw new RuntimeException(e); + } + catch (RepositoryException e) + { + throw new RuntimeException(e); + } + + // finish the stream properly if zip stream + // this is not done by the IOUtils + if (outputStream instanceof DeflaterOutputStream) + { + ((DeflaterOutputStream) outputStream).finish(); + } + + baseOutputStream.flush(); + IOUtils.closeQuietly(baseOutputStream); + } + +} Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/AbstractBootstrapSyncListener.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/BootstrapSyncListener.java =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/BootstrapSyncListener.java (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/BootstrapSyncListener.java 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,160 @@ +package it.openutils.mgnlbootstrapsync.listener; + +import it.openutils.mgnlbootstrapsync.watch.BootstrapSyncRepositoryWatch; + +import java.util.ArrayList; +import java.util.List; + +import javax.jcr.RepositoryException; +import javax.jcr.observation.Event; +import javax.jcr.observation.EventIterator; + +import org.apache.commons.lang.StringUtils; +import org.apache.jackrabbit.core.observation.EventImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author luca boati mmolaschi + * @version $Id: $ + */ +public class BootstrapSyncListener extends AbstractBootstrapSyncListener +{ + + /** + * Store operation + * @author mmolaschi + * @version $Id: $ + */ + public class JcrOperation + { + + private String path; + + private boolean remove; + + /** + * @param path path of operation + * @param remove is a remove op? + */ + public JcrOperation(String path, boolean remove) + { + this.path = path; + this.remove = remove; + } + } + + private static Logger log = LoggerFactory.getLogger(BootstrapSyncListener.class); + + /** + * Configure listener on watch + * @param watch watch + */ + public BootstrapSyncListener(BootstrapSyncRepositoryWatch watch) + { + super(watch); + } + + /** + * {@inheritDoc} + */ + @Override + public void onEvent(EventIterator events) + { + List<JcrOperation> operations = new ArrayList<JcrOperation>(); + while (events.hasNext()) + { + // Event event + EventImpl event = (EventImpl) events.nextEvent(); + String eventPath = null; + try + { + eventPath = event.getPath(); + } + catch (RepositoryException ex) + { + log.error(ex.getMessage(), ex); + continue; + } + if (eventPath.startsWith("/jcr:")) + { + return; + } + + switch (event.getType()) + { + case Event.NODE_ADDED : + log.debug(eventPath + " added"); + break; + case Event.NODE_REMOVED : + log.debug(eventPath + " removed"); + break; + case Event.PROPERTY_ADDED : + log.debug(eventPath + " added"); + break; + case Event.PROPERTY_CHANGED : + log.debug(eventPath + " changed"); + break; + case Event.PROPERTY_REMOVED : + log.debug(eventPath + " removed"); + break; + default : + break; + } + + if (event.getType() == Event.NODE_REMOVED) + { + operations.add(new JcrOperation(eventPath, true)); + } + else + { + operations.add(new JcrOperation(eventPath, false)); + } + } + + // calculate minimum path and remove operation + String basePath = null; + JcrOperation remove = null; + for (JcrOperation operation : operations) + { + if (operation.remove) + { + remove = operation; + continue; + } + + int basePathSl = StringUtils.countMatches(basePath, "/"); + int pathSl = StringUtils.countMatches(operation.path, "/"); + + if (basePath == null || pathSl < basePathSl) + { + basePath = operation.path; + } + } + + if (remove != null) + { + if (log.isDebugEnabled()) + { + log.debug("Removed PATH: " + remove.path); + } + + removeNode(remove.path); + } + + if (basePath != null) + { + // remove metadata if present + basePath = StringUtils.substringBefore(basePath, "/MetaData"); + + if (log.isDebugEnabled()) + { + log.debug("Changed PATH: " + basePath); + } + + exportNode(basePath); + } + } + +} Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/listener/BootstrapSyncListener.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/watch/BootstrapSyncRepositoryWatch.java =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/watch/BootstrapSyncRepositoryWatch.java (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/watch/BootstrapSyncRepositoryWatch.java 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,119 @@ +package it.openutils.mgnlbootstrapsync.watch; + +import it.openutils.mgnlbootstrapsync.BootstrapEnableRoot; +import it.openutils.mgnlbootstrapsync.BootstrapExportRoot; + +/** + * + * @author mmolaschi + * @version $Id: $ + */ +public class BootstrapSyncRepositoryWatch +{ + + private String repository; + + private String exportPath; + + private BootstrapExportRoot exportRoots; + + private BootstrapEnableRoot enableRoots; + + private String nodeType; + + /** + * + * @param repository repository to watch + * @param basePath base path for repository + * @param exportPath folder to export files to + * @param exportRoots comma separeted list of nodes (every modified to children will be exported as this node) + * @param enableRoots enabled branches for listener + */ + public BootstrapSyncRepositoryWatch(String repository, String exportPath, String exportRoots, String enableRoots, String nodeType) + { + this.repository = repository; + this.exportPath = exportPath; + this.exportRoots = new BootstrapExportRoot(exportRoots); + this.enableRoots = new BootstrapEnableRoot(enableRoots); + } + + public String getRepository() + { + return repository; + } + + public void setRepository(String repository) + { + this.repository = repository; + } + + public String getExportPath() + { + return exportPath; + } + + public void setExportPath(String exportPath) + { + this.exportPath = exportPath; + } + + + /** + * Returns the exportRoots. + * @return the exportRoots + */ + public BootstrapExportRoot getExportRoots() + { + return exportRoots; + } + + + /** + * Sets the exportRoots. + * @param exportRoots the exportRoots to set + */ + public void setExportRoots(BootstrapExportRoot exportRoots) + { + this.exportRoots = exportRoots; + } + + + /** + * Returns the enableRoots. + * @return the enableRoots + */ + public BootstrapEnableRoot getEnableRoots() + { + return enableRoots; + } + + + /** + * Sets the enableRoots. + * @param enableRoots the enableRoots to set + */ + public void setEnableRoots(BootstrapEnableRoot enableRoots) + { + this.enableRoots = enableRoots; + } + + + /** + * Returns the nodeType. + * @return the nodeType + */ + public String getNodeType() + { + return nodeType; + } + + + /** + * Sets the nodeType. + * @param nodeType the nodeType to set + */ + public void setNodeType(String nodeType) + { + this.nodeType = nodeType; + } +} Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/java/it/openutils/mgnlbootstrapsync/watch/BootstrapSyncRepositoryWatch.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/openutils-mgnlbootstrapsync/src/main/resources/META-INF/magnolia/bootstrapsync.xml =================================================================== --- trunk/openutils-mgnlbootstrapsync/src/main/resources/META-INF/magnolia/bootstrapsync.xml (rev 0) +++ trunk/openutils-mgnlbootstrapsync/src/main/resources/META-INF/magnolia/bootstrapsync.xml 2008-04-29 12:53:22 UTC (rev 805) @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE module SYSTEM "module.dtd"> +<module> + <name>bootstrapsync</name> + <displayName>bootstrapsync</displayName> + <description>Bootstrap Synchronizer</description> + <class>it.openutils.mgnlbootstrapsync.lifecycle.BootstrapSyncModuleLifecycle</class> + <version>${project.version}</version> +</module> Property changes on: trunk/openutils-mgnlbootstrapsync/src/main/resources/META-INF/magnolia/bootstrapsync.xml ___________________________________________________________________ Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |