/** * Copyright 2008 - 2009 Pro-Netics S.P.A. * * Licensed 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 it.pronetics.madstore.repository.jcr.impl; import it.pronetics.madstore.common.AtomConstants; import it.pronetics.madstore.common.dom.DomHelper; import it.pronetics.madstore.repository.index.IndexManager; import it.pronetics.madstore.repository.jcr.xml.JcrContentHandlerFactory; import it.pronetics.madstore.repository.support.AtomRepositoryException; import it.pronetics.madstore.repository.util.PagingList; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.jcr.ImportUUIDBehavior; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.query.Query; import javax.jcr.query.QueryManager; import javax.jcr.query.QueryResult; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.antlr.stringtemplate.StringTemplate; import org.antlr.stringtemplate.StringTemplateGroup; import org.springframework.extensions.jcr.JcrTemplate; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.ContentHandler; /** * Base abstract class for repositories implementations. * <br/> * This class contains methods to read and write content from the repository, defining its inner structure. * * @author Salvatore Incandela * @author Sergio Bossa */ public abstract class AbstractJcrRepository { private static final String TEMPLATES_CLASSPATH_FOLDER = "templates/"; private static final String GET_ENTRY_NODE_PATH_TEMPLATE = TEMPLATES_CLASSPATH_FOLDER + "getEntryNode"; private static final String GET_COLLECTION_NODE_PATH_TEMPLATE = TEMPLATES_CLASSPATH_FOLDER + "getCollectionNode"; private static final String GET_ENTRY_NODES_QUERY_TEMPLATE = TEMPLATES_CLASSPATH_FOLDER + "getEntryNodes"; private static final String GET_COLLECTION_NODES_QUERY_TEMPLATE = TEMPLATES_CLASSPATH_FOLDER + "getCollectionNodes"; private static final String COLLECTION_TEMPLATE_PARAMETER = "collection"; private static final String ENTRY_TEMPLATE_PARAMETER = "entry"; private static final StringTemplateGroup PATH_GROUP = new StringTemplateGroup("pathGroup"); private static final StringTemplateGroup QUERY_GROUP = new StringTemplateGroup("queryGroup"); private static final String MADSTORE_NAMESPACE = "mds:"; private static final String APP_COLLECTION = "app:collection"; private static final String ATOM_ENTRY = "atom:entry"; private static final String JCR_LAST_MODIFIED = "jcr:lastModified"; private static final String MIX_REFERENCEABLE = "mix:referenceable"; private static final String COLLECTION_REF = "collectionRef"; protected JcrTemplate jcrTemplate; protected JcrContentHandlerFactory jcrContentHandlerFactory; protected IndexManager indexManager; public void setJcrTemplate(JcrTemplate jcrTemplate) { this.jcrTemplate = jcrTemplate; } public void setJcrContentHandlerFactory(JcrContentHandlerFactory jcrContentHandlerFactory) { this.jcrContentHandlerFactory = jcrContentHandlerFactory; } public void setIndexManager(IndexManager indexManager) { this.indexManager = indexManager; } public IndexManager getIndexManager() { return indexManager; } protected final void importNodeFromDomCollection(String collectionKey, Element collectionElement, Session session) { try { InputStream collectionStream = DomHelper.getStreamFromDomElement(collectionElement); Node root = session.getRootNode(); Node collectionContainerNode = root.addNode(MADSTORE_NAMESPACE + collectionKey); session.importXML(collectionContainerNode.getPath(), collectionStream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); Node collectionNode = collectionContainerNode.getNode(APP_COLLECTION); postProcessCollectionImport(collectionElement, collectionContainerNode, collectionNode); } catch (Exception ex) { throw new AtomRepositoryException(ex.getMessage(), ex); } } protected final void importNodeFromDomEntry(String collectionKey, String entryKey, Element entryElement, Session session) { try { InputStream entryStream = DomHelper.getStreamFromDomElement(entryElement); Node root = session.getRootNode(); Node collectionContainerNode = root.getNode(MADSTORE_NAMESPACE + collectionKey); Node entryContainerNode = collectionContainerNode.addNode(MADSTORE_NAMESPACE + entryKey); session.importXML(entryContainerNode.getPath(), entryStream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); Node entryNode = entryContainerNode.getNode(ATOM_ENTRY); postProcessEntryImport(entryElement, collectionContainerNode, entryContainerNode, entryNode); } catch (Exception ex) { throw new AtomRepositoryException(ex.getMessage(), ex); } } protected final Element exportNodeToDom(String path, Session session) { try { Document exportedDocument = getDomDocument(); ContentHandler atomContentHandler = jcrContentHandlerFactory.makeExportContentHandler(exportedDocument); session.exportDocumentView(path, atomContentHandler, false, false); return exportedDocument.getDocumentElement(); } catch (Exception ex) { throw new AtomRepositoryException(ex.getMessage(), ex); } } protected final void postProcessCollectionImport(Element collectionElement, Node collectionContainerNode, Node collectionNode) { try { collectionContainerNode.addMixin(MIX_REFERENCEABLE); } catch (Exception ex) { throw new AtomRepositoryException(ex.getMessage(), ex); } } protected final void postProcessEntryImport(Element entryElement, Node collectionContainerNode, Node entryContainerNode, Node entryNode) { try { entryContainerNode.addMixin(MIX_REFERENCEABLE); entryContainerNode.setProperty(COLLECTION_REF, collectionContainerNode); org.w3c.dom.NodeList nodes = entryElement.getElementsByTagNameNS(AtomConstants.ATOM_NS, AtomConstants.ATOM_ENTRY_UPDATED); if (nodes.getLength() == 1) { org.w3c.dom.Node updated = nodes.item(0); entryNode.setProperty(JCR_LAST_MODIFIED, updated.getTextContent()); } } catch (Exception ex) { throw new AtomRepositoryException(ex.getMessage(), ex); } } protected final Node getCollectionNode(String collectionKey, Session session) throws RepositoryException { StringTemplate pathTemplate = PATH_GROUP.getInstanceOf(GET_COLLECTION_NODE_PATH_TEMPLATE); pathTemplate.setAttribute(COLLECTION_TEMPLATE_PARAMETER, collectionKey); String path = pathTemplate.toString(); Node root = session.getRootNode(); if (root.hasNode(path)) { return root.getNode(path); } else { return null; } } protected final Node getEntryNode(String collectionKey, String entryKey, Session session) throws RepositoryException { StringTemplate pathTemplate = PATH_GROUP.getInstanceOf(GET_ENTRY_NODE_PATH_TEMPLATE); pathTemplate.setAttribute(COLLECTION_TEMPLATE_PARAMETER, collectionKey); pathTemplate.setAttribute(ENTRY_TEMPLATE_PARAMETER, entryKey); String path = pathTemplate.toString(); Node root = session.getRootNode(); if (root.hasNode(path)) { return root.getNode(path); } else { return null; } } protected final List<Node> getCollectionNodes(Session session) throws RepositoryException { StringTemplate queryTemplate = QUERY_GROUP.getInstanceOf(GET_COLLECTION_NODES_QUERY_TEMPLATE); QueryManager queryManager = session.getWorkspace().getQueryManager(); Query query = queryManager.createQuery(queryTemplate.toString(), Query.XPATH); QueryResult queryResult = query.execute(); List<Node> elements = new ArrayList<Node>(); NodeIterator nodeIterator = queryResult.getNodes(); while (nodeIterator.hasNext()) { elements.add(nodeIterator.nextNode()); } return elements; } protected final PagingList<Node> getEntryNodes(String collectionKey, int offset, int max, Session session) throws RepositoryException { if (offset < 0 || max < 0) { throw new IllegalArgumentException("Parameters offset and max cannot be negative!"); } StringTemplate queryTemplate = QUERY_GROUP.getInstanceOf(GET_ENTRY_NODES_QUERY_TEMPLATE); queryTemplate.setAttribute(COLLECTION_TEMPLATE_PARAMETER, collectionKey); QueryManager queryManager = session.getWorkspace().getQueryManager(); Query query = queryManager.createQuery(queryTemplate.toString(), Query.XPATH); QueryResult queryResult = query.execute(); NodeIterator nodeIterator = queryResult.getNodes(); int total = (int) nodeIterator.getSize(); PagingList<Node> elements = new PagingList<Node>( new ArrayList<Node>(), offset, max, total); if (nodeIterator.getSize() > offset) { nodeIterator.skip(offset); while (nodeIterator.hasNext()) { if (max > 0 && !((nodeIterator.getPosition() - offset + 1) <= max)) { break; } elements.add(nodeIterator.nextNode()); } } return elements; } private Document getDomDocument() throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.newDocument(); } }