001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.utils;
014
015import static org.apache.juneau.internal.ClassUtils.*;
016
017import java.lang.reflect.*;
018
019import org.apache.juneau.*;
020
021/**
022 * Utility class for quick lookup of class metadata instances.
023 *
024 * <p>
025 * Class instances are created once and then cached.
026 *
027 * <p>
028 * Classes must have a constructor that takes in a single argument.
029 */
030public class MetadataMap {
031
032   private Class<?>[] classes = new Class<?>[0];
033   private Object[] metadata = new Object[0];
034
035
036   /**
037    * Constructor.
038    *
039    * @param c The metadata class to create.
040    * @param constructorArg The argument needed to construct the metadata.
041    * @return The cached metadata object.
042    */
043   @SuppressWarnings("unchecked")
044   public <T> T get(Class<T> c, Object constructorArg) {
045      for (int i = 0; i < classes.length; i++)
046         if (classes[i] == c)
047            return (T)metadata[i];
048      synchronized(this) {
049         for (int i = 0; i < classes.length; i++)
050            if (classes[i] == c)
051               return (T)metadata[i];
052         Class<?>[] classes2 = new Class<?>[classes.length + 1];
053         Object[] metadata2 = new Object[classes.length + 1];
054         for (int i = 0; i < classes.length; i++) {
055            classes2[i] = classes[i];
056            metadata2[i] = metadata[i];
057         }
058         Object o = null;
059         try {
060            for (Constructor<?> con : c.getConstructors()) {
061               Class<?>[] pt = con.getParameterTypes();
062               if (pt.length == 1 && isParentClass(pt[0], constructorArg.getClass())) {
063                  o = con.newInstance(constructorArg);
064                  break;
065               }
066            }
067         } catch (InvocationTargetException e) {
068            Throwable t = e.getTargetException();
069            if (t instanceof RuntimeException)
070               throw (RuntimeException)t;
071            throw new RuntimeException(t);
072         } catch (Exception e) {
073            throw new RuntimeException(e);
074         }
075         if (o == null)
076            throw new BeanRuntimeException(c,
077               "Could not find a constructor on class with a parameter to handle type {0}", constructorArg.getClass());
078         classes2[classes.length] = c;
079         metadata2[classes.length] = o;
080         classes = classes2;
081         metadata = metadata2;
082         return (T)o;
083      }
084   }
085}