001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.xbean.recipe; 018 019 import java.util.ArrayList; 020 import java.util.Iterator; 021 import java.util.LinkedHashMap; 022 import java.util.List; 023 import java.util.Map; 024 import java.util.SortedMap; 025 import java.util.TreeMap; 026 027 /** 028 * @version $Rev: 6687 $ $Date: 2005-12-28T21:08:56.733437Z $ 029 */ 030 public class MapRecipe extends AbstractRecipe { 031 private final List<Object[]> entries; 032 private final String type; 033 034 public MapRecipe() { 035 type = LinkedHashMap.class.getName(); 036 entries = new ArrayList<Object[]>(); 037 } 038 039 public MapRecipe(String type) { 040 this.type = type; 041 entries = new ArrayList<Object[]>(); 042 } 043 044 public MapRecipe(Class type) { 045 this.type = type.getName(); 046 if (!RecipeHelper.hasDefaultConstructor(type)) throw new IllegalArgumentException("Type does not have a default constructor " + type); 047 entries = new ArrayList<Object[]>(); 048 } 049 050 public MapRecipe(Map map) { 051 if (map == null) throw new NullPointerException("map is null"); 052 053 entries = new ArrayList<Object[]>(map.size()); 054 055 // If the specified set has a default constructor we will recreate the set, otherwise we use a LinkedHashMap or TreeMap 056 if (RecipeHelper.hasDefaultConstructor(map.getClass())) { 057 this.type = map.getClass().getName(); 058 } else if (map instanceof SortedMap) { 059 this.type = TreeMap.class.getName(); 060 } else { 061 this.type = LinkedHashMap.class.getName(); 062 } 063 putAll(map); 064 } 065 066 public MapRecipe(String type, Map map) { 067 if (map == null) throw new NullPointerException("map is null"); 068 this.type = type; 069 entries = new ArrayList<Object[]>(map.size()); 070 putAll(map); 071 } 072 073 public MapRecipe(Class type, Map map) { 074 if (map == null) throw new NullPointerException("map is null"); 075 if (!RecipeHelper.hasDefaultConstructor(type)) throw new IllegalArgumentException("Type does not have a default constructor " + type); 076 this.type = type.getName(); 077 entries = new ArrayList<Object[]>(map.size()); 078 putAll(map); 079 } 080 081 public MapRecipe(MapRecipe mapRecipe) { 082 if (mapRecipe == null) throw new NullPointerException("mapRecipe is null"); 083 this.type = mapRecipe.type; 084 entries = new ArrayList<Object[]>(mapRecipe.entries); 085 } 086 087 public boolean canCreate(Class type, ClassLoader classLoader) { 088 Class myType = getType(classLoader); 089 return type.isAssignableFrom(myType); 090 } 091 092 public Map create(ClassLoader classLoader) { 093 Class mapType = getType(classLoader); 094 095 if (!RecipeHelper.hasDefaultConstructor(mapType)) { 096 throw new ConstructionException("Type does not have a default constructor " + type); 097 } 098 099 Object o; 100 try { 101 o = mapType.newInstance(); 102 } catch (Exception e) { 103 throw new ConstructionException("Error while creating set instance: " + type); 104 } 105 106 if(!(o instanceof Map)) { 107 throw new ConstructionException("Specified map type does not implement the Map interface: " + type); 108 } 109 110 Map instance = (Map) o; 111 for (Object[] entry : entries) { 112 Object key = entry[0]; 113 if (key instanceof Recipe) { 114 Recipe recipe = (Recipe) key; 115 try { 116 key = recipe.create(classLoader); 117 } catch (ConstructionException e) { 118 e.setPrependAttributeName("[" + type + " " + key + "]"); 119 throw e; 120 } 121 } 122 123 Object value = entry[1]; 124 if (value instanceof Recipe) { 125 Recipe recipe = (Recipe) value; 126 try { 127 value = recipe.create(classLoader); 128 } catch (ConstructionException e) { 129 e.setPrependAttributeName("[" + type + " " + key + "]"); 130 throw e; 131 } 132 } 133 134 //noinspection unchecked 135 instance.put(key, value); 136 } 137 return instance; 138 } 139 140 private Class getType(ClassLoader classLoader) { 141 Class mapType = null; 142 try { 143 mapType = Class.forName(type, true, classLoader); 144 } catch (ClassNotFoundException e) { 145 throw new ConstructionException("Type class could not be found: " + type); 146 } 147 return mapType; 148 } 149 150 public void put(Object key, Object value) { 151 if (key == null) throw new NullPointerException("key is null"); 152 if (!RecipeHelper.isSimpleType(key)) { 153 key = new ValueRecipe(key); 154 } 155 if (!RecipeHelper.isSimpleType(value)) { 156 value = new ValueRecipe(value); 157 } 158 entries.add(new Object[] { key, value}); 159 } 160 161 public void putAll(Map map) { 162 if (map == null) throw new NullPointerException("map is null"); 163 for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { 164 Map.Entry entry = (Map.Entry) iterator.next(); 165 Object key = entry.getKey(); 166 Object value = entry.getValue(); 167 put(key, value); 168 } 169 } 170 }