All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jackrabbit.spi.commons.name.NameFactoryImpl Maven / Gradle / Ivy

/*
 * 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.name;

import org.apache.jackrabbit.spi.NameFactory;
import org.apache.jackrabbit.spi.Name;

/**
 * NameFactoryImpl...
 */
public class NameFactoryImpl implements NameFactory {

    private static final NameFactory INSTANCE = new NameFactoryImpl();

    /**
     * Cache of flyweight name instances.
     *
     * @see JCR-1663
     */
    private final HashCache cache = new HashCache();

    private NameFactoryImpl() {};

    public static NameFactory getInstance() {
        return INSTANCE;
    }

    //--------------------------------------------------------< NameFactory >---
    /**
     * @see NameFactory#create(String, String)
     */
    public Name create(String namespaceURI, String localName) throws IllegalArgumentException {
        // NOTE: an empty localName and/or URI is valid (e.g. the root node name)
        if (namespaceURI == null) {
            throw new IllegalArgumentException("No namespaceURI specified");
        }
        if (localName == null) {
            throw new IllegalArgumentException("No localName specified");
        }
        return cache.get(new NameImpl(namespaceURI, localName));
    }

    /**
     * @see NameFactory#create(String)
     */
    public Name create(String nameString) throws IllegalArgumentException {
        if (nameString == null || "".equals(nameString)) {
            throw new IllegalArgumentException("No Name literal specified");
        }
        if (nameString.charAt(0) != '{') {
            throw new IllegalArgumentException(
                    "Invalid Name literal: " + nameString);
        }
        int i = nameString.indexOf('}');
        if (i == -1) {
            throw new IllegalArgumentException(
                    "Invalid Name literal: " + nameString);
        }
        if (i == nameString.length() - 1) {
            throw new IllegalArgumentException(
                    "Invalid Name literal: " + nameString);
        }
        return (Name) cache.get(new NameImpl(
                nameString.substring(1, i), nameString.substring(i + 1)));
    }

    //--------------------------------------------------------< inner class >---
    /**
     * Inner class implementing the Name interface.
     */
    private static class NameImpl implements Name {

        /** The empty namespace uri */
        private static final String EMPTY = "".intern();

        /** The memorized hash code of this name. */
        private transient int hash;

        /** The memorized string representation of this name. */
        private transient String string;

        /** The internalized namespace URI of this name. */
        private final String namespaceURI;

        /** The local part of this name. */
        private final String localName;

        private NameImpl(String namespaceURI, String localName) {
            // internalize namespaceURI to improve performance of comparisons.
            if (namespaceURI.length() == 0) {
                // see JCR-2464
                this.namespaceURI = EMPTY;
            } else {
                this.namespaceURI = namespaceURI.intern();
            }
            // localName is not internalized in order not to risk huge perm
            // space for large repositories
            this.localName = localName;
            hash = 0;
        }

        //-----------------------------------------------------------< Name >---
        /**
         * @see Name#getLocalName()
         */
        public String getLocalName() {
            return localName;
        }

        /**
         * @see Name#getNamespaceURI()
         */
        public String getNamespaceURI() {
            return namespaceURI;
        }

        //---------------------------------------------------------< Object >---
        /**
         * Returns the string representation of this Name in the
         * following format:
         * 

* {namespaceURI}localName * * @return the string representation of this Name. * @see NameFactory#create(String) * @see Object#toString() */ @Override public String toString() { // Name is immutable, we can store the string representation if (string == null) { string = '{' + namespaceURI + '}' + localName; } return string; } /** * Compares two names for equality. Returns true * if the given object is a Name and has the same namespace * URI and local part as this Name. * * @param obj the object to compare. * @return true if the object is equal to this Name, * false otherwise. * @see Object#equals(Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof NameImpl) { NameImpl other = (NameImpl) obj; // we can use == operator for namespaceURI since it is internalized return namespaceURI == other.namespaceURI && localName.equals(other.localName); } // some other Name implementation if (obj instanceof Name) { Name other = (Name) obj; return namespaceURI.equals(other.getNamespaceURI()) && localName.equals(other.getLocalName()); } return false; } /** * Returns the hash code of this name. The hash code is * computed from the namespace URI and local part of the * name and memorized for better performance. * * @return hash code * @see Object#hashCode() */ @Override public int hashCode() { // Name is immutable, we can store the computed hash code value int h = hash; if (h == 0) { h = 17; h = 37 * h + namespaceURI.hashCode(); h = 37 * h + localName.hashCode(); hash = h; } return h; } //------------------------------------------------------< Cloneable >--- /** * Creates a clone of this Name. * Overridden in order to make clone() public. * * @return a clone of this instance * @throws CloneNotSupportedException never thrown * @see Object#clone() */ @Override public Object clone() throws CloneNotSupportedException { // Name is immutable, no special handling required return super.clone(); } //-----------------------------------------------------< Comparable >--- /** * Compares two Names. * * @param o the object to compare. * @return comparison result * @throws ClassCastException if the given object is not a Name. * @see Comparable#compareTo(Object) */ public int compareTo(Object o) { if (this == o) { return 0; } Name other = (Name) o; if (namespaceURI.equals(other.getNamespaceURI())) { return localName.compareTo(other.getLocalName()); } else { return namespaceURI.compareTo(other.getNamespaceURI()); } } //---------------------------------------------------< Serializable >--- /** * Creates a new Name instance using the proper constructor * during deserialization in order to make sure that internalized strings * are used where appropriate. */ private Object readResolve() { return new NameImpl(namespaceURI, localName); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy