001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.data.provider.impl;
017
018import java.util.Collection;
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.Map;
022import java.util.concurrent.ConcurrentHashMap;
023
024import org.kuali.rice.krad.data.metadata.DataObjectMetadata;
025import org.kuali.rice.krad.data.provider.MetadataProvider;
026
027/**
028 * Superclass for all metadata providers which contain the basic operations and data structure.
029 *
030 * <p>All each subclass needs to implement is the initializeMetadata method.</p>
031 *
032 * @author Kuali Rice Team (rice.collab@kuali.org)
033 */
034public abstract class MetadataProviderBase implements MetadataProvider {
035
036    /**
037     * The map of types to metadata.
038     */
039        protected ConcurrentHashMap<Class<?>, DataObjectMetadata> masterMetadataMap =
040            new ConcurrentHashMap<Class<?>, DataObjectMetadata>();
041
042        /**
043         * Performs the initialization of the provider with the given set of types.
044         *
045     * <p>
046         * If the list is null or empty, the provider is expected to discover the types via other means, or do nothing if
047     * the types cannot be discovered.
048     * </p>
049         */
050        protected abstract void initializeMetadata(Collection<Class<?>> types);
051
052    /**
053     * {@inheritDoc}
054     */
055        @Override
056        public boolean handles(Class<?> type) {
057                if (type == null) {
058                        return false;
059                }
060                if (masterMetadataMap.isEmpty()) {
061                        initializeMetadata(null);
062                }
063                return masterMetadataMap.containsKey(type);
064        }
065
066    /**
067     * {@inheritDoc}
068     */
069        @Override
070        public Collection<Class<?>> getSupportedTypes() {
071                if (masterMetadataMap.isEmpty()) {
072                        initializeMetadata(null);
073                }
074                return masterMetadataMap.keySet();
075        }
076
077    /**
078     * {@inheritDoc}
079     */
080        @Override
081        public Map<Class<?>, DataObjectMetadata> provideMetadata() {
082                return provideMetadataForTypes(null);
083        }
084
085    /**
086     * {@inheritDoc}
087     */
088        @Override
089        public Map<Class<?>, DataObjectMetadata> provideMetadataForTypes(Collection<Class<?>> types) {
090                if (masterMetadataMap.isEmpty()) {
091                        initializeMetadata(types);
092                        return Collections.unmodifiableMap(masterMetadataMap);
093                } else if (types == null || types.isEmpty()) {
094                        return Collections.unmodifiableMap(masterMetadataMap);
095                } else {
096                        HashMap<Class<?>, DataObjectMetadata> subMap = new HashMap<Class<?>, DataObjectMetadata>();
097
098                        for (Class<?> key : masterMetadataMap.keySet()) {
099                                if (types.contains(key)) {
100                                        subMap.put(key, masterMetadataMap.get(key));
101                                }
102                        }
103                        return subMap;
104                }
105        }
106
107    /**
108     * {@inheritDoc}
109     */
110        @Override
111        public DataObjectMetadata getMetadataForType(Class<?> dataObjectType) throws IllegalArgumentException {
112                if (dataObjectType == null) {
113                        throw new IllegalArgumentException("getMetadataForType: NULL passed for the dataObjectType");
114                }
115                if (masterMetadataMap.isEmpty()) {
116                        initializeMetadata(null);
117                }
118                return masterMetadataMap.get(dataObjectType);
119        }
120
121    /**
122     * Determines whether the given class can be persisted.
123     *
124     * @param clazz the class to check for persistability.
125     * @return true if the class is persistable, false otherwise.
126     */
127    protected boolean isClassPersistable(Class<?> clazz) {
128        if (masterMetadataMap.isEmpty()) {
129                        initializeMetadata(null);
130        }
131        return masterMetadataMap.containsKey(clazz);
132    }
133
134        /**
135         * {@inheritDoc}
136     *
137     * By default, providers are assumed to be able to pull the list of annotated types from somewhere.
138         */
139        @Override
140        public boolean requiresListOfExistingTypes() {
141                return false;
142        }
143}