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 java.lang.reflect.*;
016
017import org.apache.juneau.*;
018import org.apache.juneau.reflect.*;
019
020/**
021 * Utility class for quick lookup of class metadata instances.
022 *
023 * <p>
024 * Class instances are created once and then cached.
025 *
026 * <p>
027 * Classes must have a constructor that takes in a single argument.
028 */
029public class MetadataMap {
030
031   private Class<?>[] classes = new Class<?>[0];
032   private Object[] metadata = new Object[0];
033
034
035   /**
036    * Constructor.
037    *
038    * @param c The metadata class to create.
039    * @param constructorArg The argument needed to construct the metadata.
040    * @return The cached metadata object.
041    */
042   @SuppressWarnings("unchecked")
043   public <T> T get(Class<T> c, Object constructorArg) {
044      for (int i = 0; i < classes.length; i++)
045         if (classes[i] == c)
046            return (T)metadata[i];
047      synchronized(this) {
048         for (int i = 0; i < classes.length; i++)
049            if (classes[i] == c)
050               return (T)metadata[i];
051         Class<?>[] classes2 = new Class<?>[classes.length + 1];
052         Object[] metadata2 = new Object[classes.length + 1];
053         for (int i = 0; i < classes.length; i++) {
054            classes2[i] = classes[i];
055            metadata2[i] = metadata[i];
056         }
057         Object o = null;
058         try {
059            for (Constructor<?> con : c.getConstructors()) {
060               Class<?>[] pt = con.getParameterTypes();
061               if (pt.length == 1 && ClassInfo.of(pt[0]).isParentOf(constructorArg.getClass())) {
062                  o = con.newInstance(constructorArg);
063                  break;
064               }
065            }
066         } catch (InvocationTargetException e) {
067            Throwable t = e.getTargetException();
068            if (t instanceof RuntimeException)
069               throw (RuntimeException)t;
070            throw new RuntimeException(t);
071         } catch (Exception e) {
072            throw new RuntimeException(e);
073         }
074         if (o == null)
075            throw new BeanRuntimeException(c,
076               "Could not find a constructor on class with a parameter to handle type {0}", constructorArg.getClass());
077         classes2[classes.length] = c;
078         metadata2[classes.length] = o;
079         classes = classes2;
080         metadata = metadata2;
081         return (T)o;
082      }
083   }
084}