Package org.apache.jackrabbit.spi.commons.nodetype.compact

Source Code of org.apache.jackrabbit.spi.commons.nodetype.compact.CompactNodeTypeDefWriter

/*
* 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.jackrabbit.spi.commons.nodetype.compact;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.jcr.NamespaceException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeTypeDefinition;
import javax.jcr.query.qom.QueryObjectModelConstants;
import javax.jcr.version.OnParentVersionAction;

import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.QNodeDefinition;
import org.apache.jackrabbit.spi.QNodeTypeDefinition;
import org.apache.jackrabbit.spi.QPropertyDefinition;
import org.apache.jackrabbit.spi.QValue;
import org.apache.jackrabbit.spi.QValueConstraint;
import org.apache.jackrabbit.spi.commons.QNodeTypeDefinitionImpl;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
import org.apache.jackrabbit.spi.commons.namespace.SessionNamespaceResolver;
import org.apache.jackrabbit.spi.commons.nodetype.InvalidConstraintException;
import org.apache.jackrabbit.spi.commons.nodetype.constraint.ValueConstraint;
import org.apache.jackrabbit.spi.commons.query.qom.Operator;
import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
import org.apache.jackrabbit.spi.commons.value.ValueFormat;
import org.apache.jackrabbit.util.ISO9075;

/**
* Prints node type defs in a compact notation
* Print Format:
* <ex = "http://apache.org/jackrabbit/example">
* [ex:NodeType] > ex:ParentType1, ex:ParentType2
* orderable mixin
*   - ex:property (STRING) = 'default1', 'default2'
*     primary mandatory autocreated protected multiple VERSION
*     < 'constraint1', 'constraint2'
*   + ex:node (ex:reqType1, ex:reqType2) = ex:defaultType
*     mandatory autocreated protected multiple VERSION
*/
public class CompactNodeTypeDefWriter {

    /**
     * the indention string
     */
    private static final String INDENT = "  ";

    /**
     * the current namespace resolver
     */
    private final NamespaceResolver resolver;

    /**
     * the current name/path resolver
     */
    private final NamePathResolver npResolver;

    /**
     * the underlying writer
     */
    private Writer out;

    /**
     * special writer used for namespaces
     */
    private Writer nsWriter;

    /**
     * namespaces(prefixes) that are used
     */
    private final Set<String> usedNamespaces = new HashSet<String>();

    /**
     * Creates a new nodetype writer based on a session
     *
     * @param out the underlaying writer
     * @param s repository session
     * @param includeNS if <code>true</code> all used namespace decl. are also
     *                  written to the writer
     */
    public CompactNodeTypeDefWriter(Writer out, Session s, boolean includeNS) {
        this(out, new SessionNamespaceResolver(s), new DefaultNamePathResolver(s), includeNS);
    }

    /**
     * Creates a new nodetype writer based on a namespace resolver
     *
     * @param out the underlaying writer
     * @param r the naespace resolver
     * @param includeNS if <code>true</code> all used namespace decl. are also
     *                  written to the writer
     */
    public CompactNodeTypeDefWriter(Writer out, NamespaceResolver r, boolean includeNS) {
        this(out, r, new DefaultNamePathResolver(r), includeNS);
    }

    /**
     * Creates a new nodetype writer that does not include namepsaces.
     *
     * @param out the underlaying writer
     * @param r the naespace resolver
     * @param npResolver name-path resolver
     */
    public CompactNodeTypeDefWriter(Writer out,
                                    NamespaceResolver r,
                                    NamePathResolver npResolver) {
        this(out, r, npResolver, false);
    }

    /**
     * Creates a new nodetype writer
     *
     * @param out the underlaying writer
     * @param r the naespace resolver
     * @param npResolver name-path resolver
     * @param includeNS if <code>true</code> all used namespace decl. are also
     *                  written to the writer
     */
    public CompactNodeTypeDefWriter(Writer out,
                                    NamespaceResolver r,
                                    NamePathResolver npResolver,
                                    boolean includeNS) {
        this.resolver = r;
        this.npResolver = npResolver;
        if (includeNS) {
            this.out = new StringWriter();
            this.nsWriter = out;
        } else {
            this.out = out;
            this.nsWriter = null;
        }
    }

    /**
     * Writes the given list of QNodeTypeDefinition to the output writer including the
     * used namespaces.
     *
     * @param defs collection of definitions
     * @param r namespace resolver
     * @param npResolver name-path resolver
     * @param out output writer
     * @throws IOException if an I/O error occurs
     */
    public static void write(Collection<QNodeTypeDefinition> defs,
                             NamespaceResolver r,
                             NamePathResolver npResolver,
                             Writer out)
            throws IOException {
        CompactNodeTypeDefWriter w = new CompactNodeTypeDefWriter(out, r, npResolver, true);
        for (QNodeTypeDefinition def : defs) {
            w.write(def);
        }
        w.close();
    }

    /**
     * Write one QNodeTypeDefinition to this writer
     *
     * @param ntd node type definition
     * @throws IOException if an I/O error occurs
     */
    public void write(QNodeTypeDefinition ntd) throws IOException {
        writeName(ntd);
        writeSupertypes(ntd);
        writeOptions(ntd);
        writePropDefs(ntd);
        writeNodeDefs(ntd);
        out.write("\n\n");
    }

    /**
     * Write a collection of QNodeTypeDefinitions to this writer
     *
     * @param defs node type definitions
     * @throws IOException if an I/O error occurs
     */
    public void write(Collection<QNodeTypeDefinition> defs) throws IOException {
        for (QNodeTypeDefinition def : defs) {
            write(def);
        }
    }

    /**
     * Write one NodeTypeDefinition to this writer
     *
     * @param nt node type definition
     * @throws IOException if an I/O error occurs
     */
    public void write(NodeTypeDefinition nt) throws IOException {
        try {
            write(new QNodeTypeDefinitionImpl(nt, npResolver, QValueFactoryImpl.getInstance()));
        } catch (RepositoryException e) {
            throw new IOException("Error during internal conversion of nodetype definition:" + e.toString());
        }
    }

    /**
     * Flushes all pending write operations and Closes this writer. please note,
     * that the underlying writer remains open.
     *
     * @throws IOException if an I/O error occurs
     */
    public void close() throws IOException {
        if (nsWriter != null) {
            nsWriter.write("\n");
            out.close();
            nsWriter.write(((StringWriter) out).getBuffer().toString());
            out = nsWriter;
            nsWriter = null;
        }
        out.flush();
        out = null;
    }

    /**
     * write name
     * @param ntd node type definition
     * @throws IOException if an I/O error occurs
     */
    private void writeName(QNodeTypeDefinition ntd) throws IOException {
        out.write("[");
        out.write(resolve(ntd.getName()));
        out.write("]");
    }

    /**
     * write supertypes
     * @param ntd node type definition
     * @throws IOException if an I/O error occurs
     */
    private void writeSupertypes(QNodeTypeDefinition ntd) throws IOException {
        // get ordered list of supertypes, omitting nt:Base
        TreeSet<Name> supertypes = new TreeSet<Name>();
        for (Name name : ntd.getSupertypes()) {
            if (!name.equals(NameConstants.NT_BASE)) {
                supertypes.add(name);
            }
        }
        if (!supertypes.isEmpty()) {
            String delim = " > ";
            for (Name name : supertypes) {
                out.write(delim);
                out.write(resolve(name));
                delim = ", ";
            }
        }
    }

    /**
     * write options
     * @param ntd node type definition
     * @throws IOException if an I/O error occurs
     */
    private void writeOptions(QNodeTypeDefinition ntd) throws IOException {
        List<String> options = new LinkedList<String>();
        if (ntd.isAbstract()) {
            options.add(Lexer.ABSTRACT[0]);
        }
        if (ntd.hasOrderableChildNodes()) {
            options.add(Lexer.ORDERABLE[0]);
        }
        if (ntd.isMixin()) {
            options.add(Lexer.MIXIN[0]);
        }
        if (!ntd.isQueryable()) {
            options.add(Lexer.NOQUERY[0]);
        }
        if (ntd.getPrimaryItemName() != null) {
            options.add(Lexer.PRIMARYITEM[0]);
            options.add(resolve(ntd.getPrimaryItemName()));
        }
        for (int i = 0; i < options.size(); i++) {
            if (i == 0) {
                out.write("\n" + INDENT);
            } else {
                out.write(" ");
            }
            out.write(options.get(i));
        }
    }

    /**
     * write prop defs
     * @param ntd node type definition
     * @throws IOException if an I/O error occurs
     */
    private void writePropDefs(QNodeTypeDefinition ntd) throws IOException {
        for (QPropertyDefinition pd : ntd.getPropertyDefs()) {
            writePropDef(pd);
        }
    }

    /**
     * write node defs
     * @param ntd node type definition
     * @throws IOException if an I/O error occurs
     */
    private void writeNodeDefs(QNodeTypeDefinition ntd) throws IOException {
        for (QNodeDefinition nd : ntd.getChildNodeDefs()) {
            writeNodeDef(nd);
        }
    }

    /**
     * write prop def
     * @param pd property definition
     * @throws IOException if an I/O error occurs
     */
    private void writePropDef(QPropertyDefinition pd) throws IOException {
        out.write("\n" + INDENT + "- ");

        Name name = pd.getName();
        if (name.equals(NameConstants.ANY_NAME)) {
            out.write('*');
        } else {
            writeItemDefName(name);
        }

        out.write(" (");
        out.write(PropertyType.nameFromValue(pd.getRequiredType()).toLowerCase());
        out.write(")");
        writeDefaultValues(pd.getDefaultValues());
        if (pd.isMandatory()) {
            out.write(" mandatory");
        }
        if (pd.isAutoCreated()) {
            out.write(" autocreated");
        }
        if (pd.isProtected()) {
            out.write(" protected");
        }
        if (pd.isMultiple()) {
            out.write(" multiple");
        }
        if (pd.getOnParentVersion() != OnParentVersionAction.COPY) {
            out.write(" ");
            out.write(OnParentVersionAction.nameFromValue(pd.getOnParentVersion()).toLowerCase());
        }
        if (!pd.isFullTextSearchable()) {
            out.write(" nofulltext");
        }
        if (!pd.isQueryOrderable()) {
            out.write(" noqueryorder");
        }
        String[] qops = pd.getAvailableQueryOperators();
        if (qops != null && qops.length > 0) {
            List<String> opts = new ArrayList<String>(Arrays.asList(qops));
            List<String> defaultOps = Arrays.asList(Operator.getAllQueryOperators());
            if (!opts.containsAll(defaultOps)) {
                out.write(" queryops '");
                String delim = "";
                for (String opt: opts) {
                    out.write(delim);
                    delim= ", ";
                    if (opt.equals(QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO)) {
                        out.write(Lexer.QUEROPS_EQUAL);
                    } else if (opt.equals(QueryObjectModelConstants.JCR_OPERATOR_NOT_EQUAL_TO)) {
                        out.write(Lexer.QUEROPS_NOTEQUAL);
                    } else if (opt.equals(QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN)) {
                        out.write(Lexer.QUEROPS_GREATERTHAN);
                    } else if (opt.equals(QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO)) {
                        out.write(Lexer.QUEROPS_GREATERTHANOREQUAL);
                    } else if (opt.equals(QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN)) {
                        out.write(Lexer.QUEROPS_LESSTHAN);
                    } else if (opt.equals(QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO)) {
                        out.write(Lexer.QUEROPS_LESSTHANOREQUAL);
                    } else if (opt.equals(QueryObjectModelConstants.JCR_OPERATOR_LIKE)) {
                        out.write(Lexer.QUEROPS_LIKE);
                    }
                }
                out.write("'");
            }
        }
        writeValueConstraints(pd.getValueConstraints(), pd.getRequiredType());
    }

    /**
     * write default values
     * @param dva default value
     * @throws IOException if an I/O error occurs
     */
    private void writeDefaultValues(QValue[] dva) throws IOException {
        if (dva != null && dva.length > 0) {
            String delim = " = '";
            for (QValue value : dva) {
                out.write(delim);
                try {
                    String str = ValueFormat.getJCRString(value, npResolver);
                    out.write(escape(str));
                } catch (RepositoryException e) {
                    out.write(escape(value.toString()));
                }
                out.write("'");
                delim = ", '";
            }
        }
    }

    /**
     * write value constraints
     * @param vca value constraint
     * @param type value type
     * @throws IOException if an I/O error occurs
     */
    private void writeValueConstraints(QValueConstraint[] vca, int type) throws IOException {
        if (vca != null && vca.length > 0) {
            String vc = convertConstraint(vca[0], type);
            out.write(" < '");
            out.write(escape(vc));
            out.write("'");
            for (int i = 1; i < vca.length; i++) {
                vc = convertConstraint(vca[i], type);
                out.write(", '");
                out.write(escape(vc));
                out.write("'");
            }
        }
    }

    /**
     * Converts the constraint to a jcr value
     * @param vc value constraint string
     * @param type value type
     * @return converted value
     */
    private String convertConstraint(QValueConstraint vc, int type) {
        try {
            ValueConstraint c = ValueConstraint.create(type, vc.getString());
            return c.getDefinition(npResolver);
        } catch (InvalidConstraintException e) {
            // ignore -> return unconverted constraint
            return vc.getString();
        }
    }

    /**
     * write node def
     *
     * @param nd node definition
     * @throws IOException if an I/O error occurs
     */
    private void writeNodeDef(QNodeDefinition nd) throws IOException {
        out.write("\n" + INDENT + "+ ");

        Name name = nd.getName();
        if (name.equals(NameConstants.ANY_NAME)) {
            out.write('*');
        } else {
            writeItemDefName(name);
        }
        writeRequiredTypes(nd.getRequiredPrimaryTypes());
        writeDefaultType(nd.getDefaultPrimaryType());
        if (nd.isMandatory()) {
            out.write(" mandatory");
        }
        if (nd.isAutoCreated()) {
            out.write(" autocreated");
        }
        if (nd.isProtected()) {
            out.write(" protected");
        }
        if (nd.allowsSameNameSiblings()) {
            out.write(" multiple");
        }
        if (nd.getOnParentVersion() != OnParentVersionAction.COPY) {
            out.write(" ");
            out.write(OnParentVersionAction.nameFromValue(nd.getOnParentVersion()).toLowerCase());
        }
    }

    /**
     * Write item def name
     * @param name name
     * @throws IOException if an I/O error occurs
     */
    private void writeItemDefName(Name name) throws IOException {
        out.write(resolve(name));
    }
    /**
     * write required types
     * @param reqTypes required type names
     * @throws IOException if an I/O error occurs
     */
    private void writeRequiredTypes(Name[] reqTypes) throws IOException {
        if (reqTypes != null && reqTypes.length > 0) {
            String delim = " (";
            for (Name reqType : reqTypes) {
                out.write(delim);
                out.write(resolve(reqType));
                delim = ", ";
            }
            out.write(")");
        }
    }

    /**
     * write default types
     * @param defType default type name
     * @throws IOException if an I/O error occurs
     */
    private void writeDefaultType(Name defType) throws IOException {
        if (defType != null && !defType.getLocalName().equals("*")) {
            out.write(" = ");
            out.write(resolve(defType));
        }
    }

    /**
     * resolve
     * @param name name to resolve
     * @return the resolved name
     * @throws IOException if an I/O error occurs
     */
    private String resolve(Name name) throws IOException {
        if (name == null) {
            return "";
        }
        try {
            String prefix = resolver.getPrefix(name.getNamespaceURI());
            if (prefix != null && !prefix.equals(Name.NS_EMPTY_PREFIX)) {
                // check for writing namespaces
                if (nsWriter != null) {
                    if (!usedNamespaces.contains(prefix)) {
                        usedNamespaces.add(prefix);
                        nsWriter.write("<'");
                        nsWriter.write(prefix);
                        nsWriter.write("'='");
                        nsWriter.write(escape(name.getNamespaceURI()));
                        nsWriter.write("'>\n");
                    }
                }
                prefix += ":";
            }

            String encLocalName = ISO9075.encode(name.getLocalName());
            String resolvedName = prefix + encLocalName;

            // check for '-' and '+'
            if (resolvedName.indexOf('-') >= 0 || resolvedName.indexOf('+') >= 0) {
                return "'" + resolvedName + "'";
            } else {
                return resolvedName;
            }

        } catch (NamespaceException e) {
            return name.toString();
        }
    }

    /**
     * escape
     * @param s string
     * @return the escaped string
     */
    private String escape(String s) {
        StringBuffer sb = new StringBuffer(s);
        for (int i = 0; i < sb.length(); i++) {
            if (sb.charAt(i) == '\\') {
                sb.insert(i, '\\');
                i++;
            } else if (sb.charAt(i) == '\'') {
                sb.insert(i, '\'');
                i++;
            }
        }
        return sb.toString();
    }
}
TOP

Related Classes of org.apache.jackrabbit.spi.commons.nodetype.compact.CompactNodeTypeDefWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.