001 /* 002 * Copyright 2006 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 import dpml.station.util.LoggingServer; 026 027 import java.io.File; 028 import java.io.IOException; 029 import java.io.FileNotFoundException; 030 import java.lang.management.ManagementFactory; 031 import java.net.URI; 032 import java.net.URL; 033 import java.net.URLConnection; 034 import java.net.MalformedURLException; 035 import java.rmi.Remote; 036 import java.util.Properties; 037 import java.util.Map; 038 import java.util.Hashtable; 039 import java.util.ArrayList; 040 import java.util.List; 041 import java.util.Set; 042 043 import javax.management.MBeanServer; 044 import javax.management.MBeanServerConnection; 045 import javax.management.ObjectName; 046 import javax.management.MBeanException; 047 import javax.management.InstanceAlreadyExistsException; 048 import javax.management.remote.JMXServiceURL; 049 import javax.management.remote.JMXConnector; 050 import javax.management.remote.JMXConnectorFactory; 051 052 import net.dpml.transit.Artifact; 053 import net.dpml.transit.ContentHandler; 054 import net.dpml.transit.ContentManager; 055 import net.dpml.lang.DecodingException; 056 import net.dpml.util.Logger; 057 import net.dpml.util.Resolver; 058 059 import net.dpml.appliance.Appliance; 060 import net.dpml.appliance.ApplianceException; 061 import net.dpml.appliance.ApplianceManager; 062 import net.dpml.appliance.ApplianceContentManager; 063 import net.dpml.appliance.ApplianceFactory; 064 065 import dpml.station.info.ApplianceDescriptor; 066 import dpml.station.info.InfoDescriptor; 067 import dpml.station.info.ProcessDescriptor; 068 069 import org.w3c.dom.Element; 070 import org.w3c.dom.Document; 071 import org.w3c.dom.TypeInfo; 072 073 /** 074 * Content handler for the <tt>appliance</tt> artifact type. 075 * 076 * @author <a href="http://www.dpml.net">Digital Product Management Laboratory</a> 077 * @version 2.0.1 078 */ 079 public class ApplianceContentHandler extends ContentHandler implements ApplianceContentManager, ApplianceFactory 080 { 081 static final String NAMESPACE = "dpml:station"; 082 static final String TYPE = "appliance"; 083 084 private static final Logger LOGGER = new DefaultLogger( "dpml.metro.appliance" ); 085 private static final DOM3DocumentBuilder DOCUMENT_BUILDER = 086 new DOM3DocumentBuilder(); 087 088 private static final List<ApplianceManager> MANAGERS = 089 new ArrayList<ApplianceManager>(); 090 091 private static final ApplianceContentHandler SINGLETON = newApplianceContentHandler(); 092 093 private static ApplianceContentHandler newApplianceContentHandler() 094 { 095 ApplianceContentHandler handler = new ApplianceContentHandler(); 096 String flag = System.getProperty( "dpml.jmx.enabled", "false" ); 097 if( "true".equals( flag ) ) 098 { 099 try 100 { 101 MBeanServer server = ManagementFactory.getPlatformMBeanServer(); 102 Hashtable<String,String> table = new Hashtable<String,String>(); 103 table.put( "type", "Appliances" ); 104 ObjectName name = 105 ObjectName.getInstance( "net.dpml.transit", table ); 106 server.registerMBean( handler, name ); 107 } 108 catch( Exception e ) 109 { 110 e.printStackTrace(); 111 } 112 } 113 return handler; 114 } 115 116 public ApplianceContentHandler() 117 { 118 this( LOGGER ); 119 } 120 121 protected ApplianceContentHandler( Logger logger ) 122 { 123 logger.debug( "instantiating" ); 124 } 125 126 /* 127 protected MBeanServerConnection getMBeanServerConnection() throws MalformedURLException, IOException 128 { 129 String spec = System.getProperty( Station.STATION_JMX_URI_KEY ); 130 if( null != spec ) 131 { 132 JMXServiceURL url = new JMXServiceURL( spec ); 133 JMXConnector connector = JMXConnectorFactory.connect( url, null ); 134 return connector.getMBeanServerConnection(); 135 } 136 else 137 { 138 return ManagementFactory.getPlatformMBeanServer(); 139 } 140 } 141 */ 142 143 public ApplianceManager[] getApplianceManagers() 144 { 145 return MANAGERS.toArray( new ApplianceManager[0] ); 146 } 147 148 /** 149 * Returns the type thar the content handler supports. 150 * @return the content type name 151 */ 152 public String getType() 153 { 154 return TYPE; 155 } 156 157 /** 158 * Returns the content in the form of a {@link net.dpml.appliance.Appliance}. 159 * @param connection the url connection 160 * @return the application handler 161 * @exception IOException if an IO error occurs 162 */ 163 public Object getContent( URLConnection connection ) throws IOException 164 { 165 return newAppliance( connection, null ); 166 } 167 168 /** 169 * Returns the content assignable to the first recognized class in the list 170 * of suppied classes. If the class array is empty the application handler is returned. 171 * If none of the classes are recognized, null is returned. 172 * @param connection the url connection 173 * @param classes the selection class array 174 * @return the resolved instance 175 * @exception IOException if an IO error occurs 176 */ 177 public Object getContent( URLConnection connection, Class[] classes ) throws IOException 178 { 179 ApplianceDescriptor descriptor = getApplianceDescriptor( connection ); 180 return getContentForClasses( descriptor, classes ); 181 } 182 183 /** 184 * Create a new appliance using the supplied connection object. 185 * @param connection the URL connection 186 * @param partition an optional partition name 187 * @return the appliance 188 * @exception IOException if an IO error occurs 189 */ 190 public Appliance newAppliance( URLConnection connection, String partition ) throws IOException 191 { 192 ApplianceDescriptor descriptor = getApplianceDescriptor( connection ); 193 return newAppliance( partition, descriptor ); 194 } 195 196 static <T>T getContentForClass( URLConnection connection, Class<T> type ) throws IOException 197 { 198 ApplianceDescriptor descriptor = getApplianceDescriptor( connection ); 199 return getContentForClass( descriptor, type ); 200 } 201 202 private static Object getContentForClasses( ApplianceDescriptor descriptor, Class<?>[] classes ) throws IOException 203 { 204 for( Class<?> c : classes ) 205 { 206 Object value = getContentForClass( descriptor, c ); 207 if( null != value ) 208 { 209 return value; 210 } 211 } 212 return null; 213 } 214 215 private static <T>T getContentForClass( ApplianceDescriptor descriptor, Class<T> type ) throws IOException 216 { 217 if( ApplianceDescriptor.class == type ) 218 { 219 return type.cast( descriptor ); 220 } 221 else if( Appliance.class == type ) 222 { 223 String key = "" + System.identityHashCode( descriptor ); 224 Appliance appliance = newAppliance( key, descriptor ); 225 return type.cast( appliance ); 226 } 227 else 228 { 229 return null; 230 } 231 } 232 233 static final Appliance newAppliance( String key, ApplianceDescriptor descriptor ) throws IOException 234 { 235 if( null == key ) 236 { 237 throw new NullPointerException( "key" ); 238 } 239 Logger logger = getLogger(); 240 Application application = new Application( logger, key, descriptor ); 241 Appliance appliance = application.getAppliance(); 242 register( key, appliance ); 243 return appliance; 244 } 245 246 static void register( String id, Appliance appliance ) 247 { 248 if( appliance instanceof ApplianceManager ) 249 { 250 if( null == id ) 251 { 252 throw new NullPointerException( "id" ); 253 } 254 ApplianceManager manager = (ApplianceManager) appliance; 255 if( !MANAGERS.contains( manager ) ) 256 { 257 try 258 { 259 MBeanServer server = ManagementFactory.getPlatformMBeanServer(); 260 Hashtable<String, String> table = new Hashtable<String, String>(); 261 table.put( "type", "Appliances" ); 262 table.put( "name", id ); 263 ObjectName name = 264 ObjectName.getInstance( "net.dpml.transit", table ); 265 server.registerMBean( manager, name ); 266 MANAGERS.add( manager ); 267 } 268 catch( Exception e ) 269 { 270 e.printStackTrace(); 271 } 272 } 273 } 274 } 275 276 static void deregister( Appliance appliance ) 277 { 278 if( appliance instanceof ApplianceManager ) 279 { 280 ApplianceManager manager = (ApplianceManager) appliance; 281 if( MANAGERS.contains( manager ) ) 282 { 283 MANAGERS.remove( manager ); 284 } 285 } 286 } 287 288 static Appliance newAppliance( String key, URI uri ) throws IOException 289 { 290 URL url = Artifact.toURL( uri ); 291 URLConnection connection = url.openConnection(); 292 ApplianceDescriptor descriptor = getApplianceDescriptor( connection ); 293 return newAppliance( key, descriptor ); 294 } 295 296 //static final Appliance newLocalAppliance( String partition, URI codebase ) throws IOException 297 //{ 298 // return new StandardAppliance( LOGGER, partition, codebase ); 299 //} 300 301 private static ApplianceDescriptor getApplianceDescriptor( URLConnection connection ) throws IOException 302 { 303 URL url = connection.getURL(); 304 try 305 { 306 Document document = DOCUMENT_BUILDER.parse( url ); 307 final Element element = document.getDocumentElement(); 308 TypeInfo type = element.getSchemaTypeInfo(); 309 String namespace = type.getTypeNamespace(); 310 if( NAMESPACE.equals( namespace ) ) 311 { 312 URI uri = URI.create( url.toExternalForm() ); 313 Resolver resolver = new SimpleResolver(); 314 return new ApplianceDescriptor( element, resolver, uri ); 315 } 316 else 317 { 318 final String error = 319 "ApplianceDescriptor namespace not recognized." 320 + "\nFound: " + namespace 321 + "\nExpecting: " + NAMESPACE; 322 throw new DecodingException( error, element ); 323 } 324 } 325 catch( IOException e ) 326 { 327 throw e; 328 } 329 catch( Exception e ) 330 { 331 final String error = "Unexpected error while constructing application profile: " + url; 332 IOException ioe = new IOException(); 333 ioe.initCause( e ); 334 throw ioe; 335 } 336 } 337 338 private static Logger getLogger() 339 { 340 return LOGGER; 341 } 342 }