001 /* 002 * Copyright 2007 Stephen 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.station; 020 021 import dpml.lang.DOM3DocumentBuilder; 022 import dpml.util.SimpleResolver; 023 import dpml.util.ElementHelper; 024 import dpml.util.DefaultLogger; 025 026 import dpml.station.info.EntryDescriptor; 027 import dpml.station.info.PlanDescriptor; 028 029 import java.io.IOException; 030 import java.net.URI; 031 import java.net.URL; 032 import java.net.URLConnection; 033 import java.lang.management.ManagementFactory; 034 import java.util.Hashtable; 035 036 import javax.management.MBeanServer; 037 import javax.management.ObjectName; 038 import javax.management.MBeanException; 039 import javax.management.InstanceAlreadyExistsException; 040 041 import net.dpml.appliance.Appliance; 042 import net.dpml.appliance.ApplianceFactory; 043 044 import net.dpml.lang.DecodingException; 045 046 import net.dpml.transit.Artifact; 047 import net.dpml.transit.ContentHandler; 048 049 import net.dpml.util.Resolver; 050 import net.dpml.util.Logger; 051 052 import org.w3c.dom.Element; 053 import org.w3c.dom.Document; 054 import org.w3c.dom.TypeInfo; 055 056 /** 057 * Content handler for the <tt>plan</tt> artifact type. 058 * 059 * @author <a href="http://www.dpml.net">Digital Product Management Laboratory</a> 060 * @version 2.0.1 061 */ 062 public class PlanContentHandler extends ApplianceContentHandler //implements ApplianceFactory 063 { 064 private static final Logger LOGGER = new DefaultLogger( "dpml.station.plan" ); 065 static final String NAMESPACE = "dpml:station"; 066 static final String TYPE = "plan"; 067 068 private static final DOM3DocumentBuilder DOCUMENT_BUILDER = 069 new DOM3DocumentBuilder(); 070 071 public PlanContentHandler() 072 { 073 super( LOGGER ); 074 } 075 076 /** 077 * Returns the type thar the content handler supports. 078 * @return the content type name 079 */ 080 public String getType() 081 { 082 return TYPE; 083 } 084 085 /** 086 * Returns the content in the form of a {@link net.dpml.appliance.Appliance}. 087 * @param connection the url connection 088 * @return the application handler 089 * @exception IOException if an IO error occurs 090 */ 091 public Object getContent( URLConnection connection ) throws IOException 092 { 093 return getContentForClass( connection, Appliance.class ); 094 } 095 096 /** 097 * Returns the content assignable to the first recognized class in the list 098 * of suppied classes. If the class array is empty the application handler is returned. 099 * If none of the classes are recognized, null is returned. 100 * @param connection the url connection 101 * @param classes the selection class array 102 * @return the resolved instance 103 * @exception IOException if an IO error occurs 104 */ 105 public Object getContent( URLConnection connection, Class[] classes ) throws IOException 106 { 107 PlanDescriptor descriptor = getPlanDescriptor( connection ); 108 return getContentForClasses( descriptor, classes ); 109 } 110 111 /** 112 * Create a new appliance using the supplied connection object. 113 * @param connection the URL connection 114 * @param partition an optional partition name 115 * @return the appliance 116 * @exception IOException if an IO error occurs 117 */ 118 public Appliance newAppliance( URLConnection connection, String partition ) throws IOException 119 { 120 PlanDescriptor descriptor = getPlanDescriptor( connection ); 121 String name = descriptor.getName(); 122 String path = getQualifiedName( partition, name ); 123 Appliance appliance = new CompositeAppliance( LOGGER, path, descriptor ); 124 register( path, appliance ); 125 return appliance; 126 } 127 128 private static String getQualifiedName( String partition, String name ) 129 { 130 if( null == partition ) 131 { 132 return name; 133 } 134 else 135 { 136 return partition + "." + name; 137 } 138 } 139 140 static <T>T getContentForClass( URLConnection connection, Class<T> type ) throws IOException 141 { 142 PlanDescriptor descriptor = getPlanDescriptor( connection ); 143 return getContentForClass( descriptor, type ); 144 } 145 146 private static Object getContentForClasses( 147 PlanDescriptor descriptor, Class<?>[] classes ) throws IOException 148 { 149 for( Class<?> c : classes ) 150 { 151 Object value = getContentForClass( descriptor, c ); 152 if( null != value ) 153 { 154 return value; 155 } 156 } 157 return null; 158 } 159 160 private static <T>T getContentForClass( 161 PlanDescriptor descriptor, Class<T> type ) throws IOException 162 { 163 if( PlanDescriptor.class == type ) 164 { 165 return type.cast( descriptor ); 166 } 167 else if( Appliance.class == type ) 168 { 169 String name = descriptor.getName(); 170 CompositeAppliance appliance = new CompositeAppliance( LOGGER, name, descriptor ); 171 register( name, appliance ); 172 return type.cast( appliance ); 173 } 174 else 175 { 176 return null; 177 } 178 } 179 180 public static Appliance newAppliance( String key, URI uri ) throws IOException 181 { 182 URL url = Artifact.toURL( uri ); 183 URLConnection connection = url.openConnection(); 184 PlanDescriptor descriptor = getPlanDescriptor( connection ); 185 Appliance appliance = new CompositeAppliance( LOGGER, key, descriptor ); 186 register( key, appliance ); 187 return appliance; 188 } 189 190 private static PlanDescriptor getPlanDescriptor( URLConnection connection ) throws IOException 191 { 192 URL url = connection.getURL(); 193 try 194 { 195 Document document = DOCUMENT_BUILDER.parse( url ); 196 final Element element = document.getDocumentElement(); 197 TypeInfo type = element.getSchemaTypeInfo(); 198 String namespace = type.getTypeNamespace(); 199 if( NAMESPACE.equals( namespace ) ) 200 { 201 URI codebase = url.toURI(); 202 Resolver resolver = new SimpleResolver(); 203 return new PlanDescriptor( element, resolver, codebase ); 204 } 205 else 206 { 207 final String error = 208 "Document namespace not recognized." 209 + "\nFound: " + namespace 210 + "\nExpecting: " + NAMESPACE; 211 throw new DecodingException( error, element ); 212 } 213 } 214 catch( IOException e ) 215 { 216 throw e; 217 } 218 catch( Exception e ) 219 { 220 final String error = "Unexpected error while constructing scenario: " + url; 221 IOException ioe = new IOException(); 222 ioe.initCause( e ); 223 throw ioe; 224 } 225 } 226 }