001 /* 002 * Copyright (c) 2005 Stephen J. McConnell 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.metro.tools; 020 021 import java.io.IOException; 022 import java.util.LinkedList; 023 import java.util.List; 024 import java.beans.IntrospectionException; 025 026 import net.dpml.metro.info.Type; 027 import net.dpml.metro.info.PartReference; 028 029 import net.dpml.tools.tasks.GenericTask; 030 031 import org.apache.tools.ant.BuildException; 032 import org.apache.tools.ant.DynamicElementNS; 033 import org.apache.tools.ant.Location; 034 import org.apache.tools.ant.Project; 035 import org.apache.tools.ant.Task; 036 037 /** 038 * A datatype that enables custom part builders. 039 * 040 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 041 * @version 1.2.0 042 */ 043 public class PartsDataType extends GenericTask implements DynamicElementNS 044 { 045 private List m_builders = new LinkedList(); 046 private Task m_owner; 047 048 /** 049 * Creation of a new parts data type. 050 * @param owner the owning task 051 */ 052 public PartsDataType( Task owner ) 053 { 054 Project proj = owner.getProject(); 055 setProject( proj ); 056 m_owner = owner; 057 } 058 059 /** 060 * Create a new component builder task. 061 * @return a new component builder task 062 */ 063 public ComponentBuilderTask createComponent() 064 { 065 ComponentBuilderTask builder = new ComponentBuilderTask(); 066 m_builders.add( builder ); 067 return builder; 068 } 069 070 /** 071 * Create a new part datatype. 072 * @return the nwew part datatype 073 */ 074 public PartDataType createPart() 075 { 076 PartDataType builder = new PartDataType(); 077 m_builders.add( builder ); 078 return builder; 079 } 080 081 /** 082 * Create a new constructed value builder. 083 * @return a part builder 084 */ 085 public EntryDataType createValue() 086 { 087 final EntryDataType builder = new EntryDataType(); 088 m_builders.add( builder ); 089 return builder; 090 } 091 092 /** 093 * Operation used to construct a custom part type directive. 094 * @param uri the part handler uri 095 * @param name the element name 096 * @param qualified the qualified name 097 * @return a dynamic part builder 098 */ 099 public Object createDynamicElement( String uri, String name, String qualified ) 100 { 101 String path = getProject().replaceProperties( uri ); 102 PartReferenceBuilder builder = loadPartHandler( path, name ); 103 if( null != builder ) 104 { 105 m_builders.add( builder ); 106 } 107 return builder; 108 } 109 110 private PartReferenceBuilder loadPartHandler( String uri, String name ) throws BuildException 111 { 112 String urn = uri + ":" + name; 113 Object builder = null; 114 PartReferenceBuilder partBuilder = null; 115 String target = m_owner.getOwningTarget().getName(); 116 Location location = m_owner.getLocation(); 117 ClassLoader context = Thread.currentThread().getContextClassLoader(); 118 try 119 { 120 Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); 121 Project proj = getProject(); 122 builder = proj.createDataType( urn ); 123 partBuilder = (PartReferenceBuilder) builder; 124 return partBuilder; 125 } 126 catch( ClassCastException e ) 127 { 128 final String error = 129 "The custom part builder [" 130 + builder.getClass().getName() 131 + "] established by the uri [" 132 + urn 133 + "] declared by the element <" 134 + name 135 + "> under the task <" 136 + m_owner.getTaskName() 137 + "><parts> within the target <" 138 + target 139 + "> does not implement the net.dpml.metro.tools.PartReferenceBuilder interface."; 140 throw new BuildException( error, e ); 141 } 142 catch( BuildException e ) 143 { 144 final String error = 145 "Unable to load the plugin from the uri [" 146 + urn 147 + "] to handle the custom part type declared by the element <" 148 + name 149 + "> within <" 150 + m_owner.getTaskName() 151 + "><parts> under the target <" 152 + target 153 + ">."; 154 throw new BuildException( error, e ); 155 } 156 catch( Throwable e ) 157 { 158 final String error = 159 "Unexpected exception while attempting to load the custom part handler with the uri [" 160 + urn 161 + "] declared by the element <" 162 + name 163 + "> within <" 164 + m_owner.getTaskName() 165 + "><parts> under the target <" 166 + target 167 + ">."; 168 throw new BuildException( error, e ); 169 } 170 finally 171 { 172 Thread.currentThread().setContextClassLoader( context ); 173 } 174 } 175 176 /** 177 * Return the set of parts contained within this container. 178 * @return the contained parts 179 */ 180 public PartReferenceBuilder[] getPartBuilders() 181 { 182 return (PartReferenceBuilder[]) m_builders.toArray( new PartReferenceBuilder[0] ); 183 } 184 185 /** 186 * Return the set of parts contained within this parts collection. 187 * @param classloader the runtime classloader 188 * @param type the component type that references are relative to 189 * @return the contained parts 190 * @exception IntrospectionException if a class introspection error occurs 191 * @exception IOException if an I/O error occurs 192 * @exception ClassNotFoundException if a part class cannot be found 193 */ 194 public PartReference[] getParts( ClassLoader classloader, Type type ) 195 throws IntrospectionException, IOException, ClassNotFoundException 196 { 197 PartReferenceBuilder[] builders = 198 (PartReferenceBuilder[]) m_builders.toArray( new PartReferenceBuilder[0] ); 199 PartReference[] parts = new PartReference[ builders.length ]; 200 for( int i=0; i<builders.length; i++ ) 201 { 202 PartReferenceBuilder builder = builders[i]; 203 parts[i] = builder.buildPartReference( classloader, type ); 204 } 205 return parts; 206 } 207 }