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}