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

org.usergrid.services.ServiceInfo Maven / Gradle / Ivy

There is a newer version: 0.0.27.1
Show newest version
/*******************************************************************************
 * Copyright 2012 Apigee Corporation
 * 
 * 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.usergrid.services;

import static org.apache.commons.lang.StringUtils.capitalize;
import static org.apache.commons.lang.StringUtils.removeEnd;
import static org.apache.commons.lang.StringUtils.split;
import static org.usergrid.utils.InflectionUtils.pluralize;
import static org.usergrid.utils.InflectionUtils.singularize;
import static org.usergrid.utils.StringUtils.stringOrSubstringAfterLast;
import static org.usergrid.utils.StringUtils.stringOrSubstringBeforeFirst;
import static org.usergrid.utils.StringUtils.stringOrSubstringBeforeLast;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import org.usergrid.persistence.Schema;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;

public class ServiceInfo {

	private final String name;
	private final boolean rootService;
	private final String rootType;
	private final String containerType;
	private final String collectionName;
	private final String itemType;
	private final List patterns;
	private final List collections;
	
	/**
	 * Pre calced since we cache this class
	 */
	private int hashCode;

	public ServiceInfo(String name, boolean rootService, String rootType,
			String containerType, String collectionName, String itemType,
			List patterns, List collections) {
		this.name = name;
		this.rootService = rootService;
		this.rootType = rootType;
		this.containerType = containerType;
		this.collectionName = collectionName;
		this.itemType = itemType;
		this.patterns = patterns;
		this.collections = collections;
		
		Hasher hasher =  Hashing.md5().newHasher();
		
		for(String pattern: patterns){
		    hasher.putString(pattern);
		}
		
		hashCode = hasher.hash().asInt();
	}

	public static String normalizeServicePattern(String s) {
		if (s == null) {
			return null;
		}
		s = s.trim().toLowerCase();

		s = removeEnd(s, "/");
		s = removeEnd(s, "/*");

		if (!s.startsWith("/")) {
			s = "/" + s;
		}

		return s;
	}

	public static List getPatterns(String servicePattern) {

		String[] collections = split(servicePattern, "/*/");
		return getPatterns(servicePattern, collections);
	}

	public static List getPatterns(String servicePattern,
			String[] collections) {

		if (collections == null) {
			collections = split(servicePattern, "/*/");
		}

		List patterns = new ArrayList();
		patterns.add(servicePattern);
		if (servicePattern.indexOf(':') >= 0) {
			patterns.add(removeTypeSpecifiers(collections));
		}

		String s = getFallbackPattern(collections, 0, collections.length - 1);
		while (s != null) {
			patterns.add(s);
			s = getFallbackPattern(s);
		}

		return patterns;

	}

	private static String removeTypeSpecifiers(String[] collections) {
		String s = "";
		boolean first = true;

		for (String collection : collections) {
			if (!first) {
				s += "/*";
			}
			first = false;
			s += "/" + stringOrSubstringBeforeFirst(collection, ':');
		}
		return s;
	}

	private static String getFallbackPattern(String servicePattern) {
		String[] collections = split(servicePattern, "/*/");
		return getFallbackPattern(collections, 0, collections.length - 1);
	}

	private static String getFallbackPattern(String[] collections, int first,
			int last) {

		if (last < first) {
			return null;
		}

		if ((last - first) == 1) {
			if (!collections[first].startsWith("entities")) {
				return "/entities:" + singularize(collections[first]) + "/*/"
						+ collections[first + 1];
			}
			return null;
		}

		if ((last - first) == 0) {
			if (!collections[first].startsWith("entities")) {
				return "/entities:" + singularize(collections[first]);
			}
			return null;
		}

		int i = last - 1;
		while (i >= first) {
			if (collections[i].indexOf(':') > -1) {
				break;
			}
			i--;
		}

		if (i >= first) {
			String type = stringOrSubstringAfterLast(collections[i], ':');
			String fallback = "/" + pluralize(type);
			i++;
			while (i <= last) {
				fallback += "/*/" + collections[i];
				i++;
			}
			return fallback;
		}

		String eType = determineType(collections, first, last - 1);
		if (eType != "entity") {
			return "/entities:" + eType + "/*/" + collections[last];
		}

		return "/entities/*/" + collections[last];

	}

	public static String determineType(String servicePattern) {

		String[] collections = split(servicePattern, '/');
		return determineType(collections, 0, collections.length - 1);
	}

	private static String determineType(String[] collections, int first,
			int last) {

		if (last < first) {
			return null;
		}

		if (first == last) {
			return singularize(stringOrSubstringAfterLast(collections[0], ':'));
		}

		int i = first + 1;
		String containerType = singularize(collections[first]);

		while (i <= last) {
			String collectionName = stringOrSubstringBeforeFirst(
					collections[i], ':');
			String nextType = Schema.getDefaultSchema().getCollectionType(
					containerType, collectionName);
			if (nextType == null) {
				if (collections[i].indexOf(':') >= 0) {
					nextType = stringOrSubstringAfterLast(collections[i], ':');
				} else if ((i < last) && (collections[last].indexOf(':') >= 0)) {
					nextType = stringOrSubstringAfterLast(collections[last],
							':');
				} else {
					return "entity";
				}
			}
			containerType = nextType;
			i++;
		}
		return containerType;
	}

    /**
     * Hold servicePattern names in a fixed size cache
     */
    private static LoadingCache servicePatternCache = CacheBuilder.newBuilder()
            .maximumSize(5000)
            .build(
                    new CacheLoader() {
                        public String load(String key) { // no checked exception
                            return _getClassName(key);
                        }
                    });

    /**
     * Delegates to _getClassName via a CacheLoader due to the expense of path name calculation
     * @param servicePattern
     * @return
     */
    public static String getClassName(String servicePattern) {
        try {
            return servicePatternCache.get(servicePattern);
        } catch (ExecutionException ee) {
            ee.printStackTrace();
        }
        return _getClassName(servicePattern);
    }

	private static String _getClassName(String servicePattern) {
		servicePattern = normalizeServicePattern(servicePattern);

		String[] collections = split(servicePattern, "/*/");

		if (collections[0].startsWith("entities")) {
			if (collections.length == 1) {
				return "generic.RootCollectionService";
			}
			if (collections[0].indexOf(':') < 0) {
				return "generic.GenericConnectionsService";
			}
			String container = stringOrSubstringAfterLast(collections[0], ':');
			String collectionName = stringOrSubstringBeforeFirst(
					collections[1], ':');
			if (Schema.getDefaultSchema().hasCollection(container,
					collectionName)) {
				return "generic.GenericCollectionService";
			}
			return "generic.GenericConnectionsService";
		}

		String packages = "";

		String types = "";

		if (collections.length == 1) {
			packages = stringOrSubstringBeforeLast(
					stringOrSubstringBeforeFirst(collections[0], ':'), '.')
					+ ".";
		} else {
			for (int i = 0; i < collections.length; i++) {
				if (i == 0) {
					packages = stringOrSubstringBeforeFirst(collections[i], ':')
							+ ".";
				} else {
					packages += stringOrSubstringBeforeLast(
							stringOrSubstringBeforeFirst(collections[i], ':'),
							'.')
							+ ".";
				}
				if ((i < (collections.length - 1))
						&& (collections[i].indexOf(':') >= 0)) {
					types += capitalize(stringOrSubstringAfterLast(
							stringOrSubstringAfterLast(collections[i], ':'),
							'.'));
				}
			}
		}

		return packages
				+ types
				+ capitalize(stringOrSubstringAfterLast(
						stringOrSubstringBeforeFirst(
								collections[collections.length - 1], ':'), '.'))
				+ "Service";

	}

	private static final Map serviceInfoCache = new LinkedHashMap();

	public static ServiceInfo getServiceInfo(String servicePattern) {
		if (servicePattern == null) {
			return null;
		}

		servicePattern = normalizeServicePattern(servicePattern);

		ServiceInfo info = serviceInfoCache.get(servicePattern);

		if (info != null) {
			return info;
		}

		String[] collections = split(servicePattern, "/*/");

		if (collections.length == 0) {
			return null;
		}

		String collectionName = stringOrSubstringBeforeFirst(
				collections[collections.length - 1], ':');

		if (collectionName == null) {
			throw new NullPointerException("Collection name is null");
		}

		String ownerType = "entity";

		String rootType = determineType(collections, 0, 0);

		if (collections.length == 1) {
			ownerType = "application";
		}

		if (collections.length > 1) {
			ownerType = determineType(collections, 0, collections.length - 2);
		}

		String itemType = determineType(collections, 0, collections.length - 1);

		List patterns = getPatterns(servicePattern, collections);
		info = new ServiceInfo(servicePattern, collections.length == 1,
				rootType, ownerType, collectionName, itemType, patterns,
				Arrays.asList(collections));

		serviceInfoCache.put(servicePattern, info);

		return info;
	}

	public String getClassName() {
		return getClassName(name);
	}

	public String getName() {
		return name;
	}

	public boolean isRootService() {
		return rootService;
	}

	public String getRootType() {
		return rootType;
	}

	public boolean isGenericRootType() {
		return ("entity".equals(rootType)) || ("entities".equals(rootType));
	}

	public String getContainerType() {
		return containerType;
	}

	public boolean isContainerType() {
		return ("entity".equals(containerType))
				|| ("entities".equals(containerType));
	}

	public String getCollectionName() {
		return collectionName;
	}

	public String getItemType() {
		return itemType;
	}

	public boolean isGenericItemType() {
		return "entity".equals(itemType);
	}

	public List getPatterns() {
		return patterns;
	}

	public List getCollections() {
		return collections;
	}

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof ServiceInfo){
            return hashCode == ((ServiceInfo)obj).hashCode;
        }
        
        return false;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        return hashCode;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy