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 && getClassInfo(pt[0]).isParentOf(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}