org.onehippo.repository.bootstrap.util.ContentFileInfo.java Source code

Java tutorial

Introduction

Here is the source code for org.onehippo.repository.bootstrap.util.ContentFileInfo.java

Source

/*
 * Copyright 2014 Hippo B.V. (http://www.onehippo.com)
 *
 * 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 org.onehippo.repository.bootstrap.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import static org.apache.jackrabbit.spi.commons.name.NameConstants.SV_NAME;
import static org.apache.jackrabbit.spi.commons.name.NameConstants.SV_NODE;
import static org.hippoecm.repository.api.HippoNodeType.HIPPO_CONTENTRESOURCE;
import static org.hippoecm.repository.api.HippoNodeType.HIPPO_CONTENTROOT;
import static org.onehippo.repository.bootstrap.util.BootstrapUtils.getResource;
import static org.onehippo.repository.xml.EnhancedSystemViewConstants.COMBINE;
import static org.onehippo.repository.xml.EnhancedSystemViewConstants.ESV_URI;
import static org.onehippo.repository.xml.EnhancedSystemViewConstants.MERGE;
import static org.onehippo.repository.xml.EnhancedSystemViewConstants.OVERLAY;

public class ContentFileInfo {

    public final List<String> contextPaths;
    public final String deltaDirective;

    private ContentFileInfo(final List<String> contextPaths, final String deltaDirective) {
        this.contextPaths = contextPaths;
        this.deltaDirective = deltaDirective;
    }

    public boolean isMerge() {
        return "combine".equals(deltaDirective) || "overlay".equals(deltaDirective);
    }

    public static ContentFileInfo readInfo(final Node item) {
        ContentFileInfoReader contentFileInfoReader = null;
        InputStream in = null;
        String contentResource = null;
        try {
            contentResource = StringUtils.trim(item.getProperty(HIPPO_CONTENTRESOURCE).getString());
            if (contentResource.endsWith(".zip") || contentResource.endsWith(".jar")) {
                return null;
            }
            final String contentRoot = StringUtils.trim(item.getProperty(HIPPO_CONTENTROOT).getString());
            contentFileInfoReader = new ContentFileInfoReader(contentRoot);
            final URL contentResourceURL = getResource(item, contentResource);
            if (contentResourceURL != null) {
                in = contentResourceURL.openStream();
                SAXParserFactory factory = SAXParserFactory.newInstance();
                factory.setNamespaceAware(true);
                factory.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
                factory.newSAXParser().parse(new InputSource(in), contentFileInfoReader);
            }
        } catch (ContentFileInfoReadingShortCircuitException ignore) {
        } catch (FactoryConfigurationError | SAXException | ParserConfigurationException | IOException
                | RepositoryException e) {
            BootstrapConstants.log.error("Could not read root node name from content file {}", contentResource, e);
        } finally {
            IOUtils.closeQuietly(in);
        }
        return contentFileInfoReader == null ? null : contentFileInfoReader.getContentFileInfo();
    }

    private static class ContentFileInfoReader extends DefaultHandler {

        private final Stack<String> path = new Stack<>();
        private final List<String> contextPaths = new ArrayList<>();
        private final String contentRoot;
        private String deltaDirective;
        private int depth = -1;

        private ContentFileInfoReader(final String contentRoot) {
            this.contentRoot = contentRoot.equals("/") ? "" : contentRoot;
        }

        @Override
        public void startElement(final String uri, final String localName, final String qName,
                final org.xml.sax.Attributes atts) throws SAXException {
            final Name name = NameFactoryImpl.getInstance().create(uri, localName);
            if (name.equals(SV_NODE)) {
                if (skip()) {
                    depth++;
                    return;
                }
                final String svName = atts.getValue(SV_NAME.getNamespaceURI(), SV_NAME.getLocalName());
                final String esvMerge = atts.getValue(ESV_URI, MERGE);
                if (contextPaths.isEmpty()) {
                    path.push(svName);
                    contextPaths.add(getCurrenContextPath());
                    deltaDirective = esvMerge;
                    if (!isMergeCombine(esvMerge)) {
                        throw new ContentFileInfoReadingShortCircuitException();
                    }
                } else {
                    if (isMergeCombine(esvMerge)) {
                        path.push(svName);
                        contextPaths.add(getCurrenContextPath());
                    } else {
                        depth++;
                    }
                }
            }
        }

        @Override
        public void endElement(final String uri, final String localName, final String qName) throws SAXException {
            final Name name = NameFactoryImpl.getInstance().create(uri, localName);
            if (name.equals(SV_NODE)) {
                if (skip()) {
                    depth--;
                } else {
                    path.pop();
                }
            }
        }

        private boolean isMergeCombine(final String esvMerge) {
            return COMBINE.equals(esvMerge) || OVERLAY.equals(esvMerge);
        }

        private ContentFileInfo getContentFileInfo() {
            if (!contextPaths.isEmpty()) {
                return new ContentFileInfo(contextPaths, deltaDirective);
            }
            return null;
        }

        private String getCurrenContextPath() {
            StringBuilder sb = new StringBuilder(contentRoot);
            for (String pathElement : path) {
                sb.append("/").append(pathElement);
            }
            return sb.toString();
        }

        private boolean skip() {
            return depth > -1;
        }
    }

    private static class ContentFileInfoReadingShortCircuitException extends SAXException {
    }

}