/* * This file is protected by Copyright. Please refer to the COPYRIGHT file * distributed with this source distribution. * * This file is part of REDHAWK core. * * REDHAWK core is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * REDHAWK core is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ /** * * Identification: $Revision$ */ package org.ossie.component; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Properties; import java.io.FileOutputStream; import java.io.File; import java.util.UUID; import java.util.Set; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.LogManager; import org.apache.log4j.PatternLayout; import org.apache.log4j.Layout; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Appender; import org.apache.log4j.Level; import org.omg.CORBA.ORB; import org.omg.CORBA.Any; import org.omg.CORBA.UserException; import org.omg.CORBA.ORBPackage.InvalidName; import org.omg.CosNaming.NameComponent; import org.omg.CosNaming.NamingContextExt; import org.omg.CosNaming.NamingContextExtHelper; import org.omg.CosNaming.NamingContext; import org.omg.CosNaming.NamingContextHelper; import org.omg.CosNaming.NamingContextPackage.CannotProceed; import org.omg.CosNaming.NamingContextPackage.NotFound; import org.omg.PortableServer.POA; import org.omg.PortableServer.POAHelper; import org.omg.PortableServer.Servant; import org.omg.PortableServer.POAManagerPackage.AdapterInactive; import org.omg.PortableServer.POAPackage.ObjectNotActive; import org.omg.PortableServer.POAPackage.ServantAlreadyActive; import org.omg.PortableServer.POAPackage.ServantNotActive; import org.omg.PortableServer.POAPackage.WrongPolicy; import org.ossie.events.PropertyEventSupplier; import org.ossie.properties.IProperty; import org.ossie.properties.PropertyListener; import org.ossie.properties.AnyUtils; import org.ossie.properties.StructProperty; import org.ossie.properties.StructDef; import org.ossie.logging.logging; import org.ossie.redhawk.DomainManagerContainer; import org.ossie.corba.utils.*; import CF.AggregateDevice; import CF.AggregateDeviceHelper; import CF.DataType; import CF.Device; import CF.DeviceHelper; import CF.ApplicationRegistrar; import CF.ApplicationRegistrarHelper; import CF.DeviceManager; import CF.DeviceManagerHelper; import CF.InvalidObjectReference; import CF.LogLevels; import CF.PortPOA; import CF.PropertiesHolder; import CF.PropertiesHelper; import CF.ResourceHelper; import CF.ResourceOperations; import CF.ResourcePOA; import CF.ResourcePOATie; import CF.UnknownProperties; import CF.UnknownIdentifier; import CF.InvalidIdentifier; import CF.LifeCyclePackage.InitializeError; import CF.LifeCyclePackage.ReleaseError; import CF.PortSetPackage.PortInfoType; import CF.PortSupplierPackage.UnknownPort; import CF.PropertyEmitterPackage.AlreadyInitialized; import CF.PropertySetPackage.InvalidConfiguration; import CF.PropertySetPackage.PartialConfiguration; import CF.ResourcePackage.StartError; import CF.ResourcePackage.StopError; import CF.TestableObjectPackage.UnknownTest; public abstract class Resource extends Logging implements ResourceOperations, Runnable { // SUPPRESS CHECKSTYLE Name /** * LoggingListener * This interface allows developers to modify the normal behavior when a request to * change the logging level or configuration context. * * Developers can provide an interface to the Resource through the * setNewLoggingListener method. */ public interface LoggingListener extends Logging.ConfigurationChangeListener { }; class PropertyChangeProcessor implements ThreadedComponent, Runnable { private Resource rsc = null; private ProcessThread _processThread=null; public PropertyChangeProcessor( Resource inRsc ) { rsc = inRsc; this._processThread = new ProcessThread(this); } public void run () { this._processThread.run(); } public void start () { this._processThread.start(); } public void stop () { this._processThread.stop(); } public int process () { if ( rsc != null ) { return rsc._propertyChangeServiceFunction(); } else { return NOOP; } } public float getThreadDelay (){ return this._processThread.getDelay(); } public void setThreadDelay (float delay) { this._processThread.setDelay(delay); } } public static Logger logger = Logger.getLogger(Resource.class.getName()); public static logging.ResourceCtx loggerCtx = null; protected CF.Resource resource; protected DomainManagerContainer _domMgr = null; protected org.ossie.events.Manager _ecm = null; /** * The CORBA ORB to use for servicing requests */ protected org.omg.CORBA.ORB orb = null; /** The POA object that this object should use for any CORBA objects it creates*/ protected POA poa = null; /** The component ID */ protected String compId; /** The component name */ protected String compName; /** Map of input ports for this resource */ protected Hashtable<String, Object> portObjects; /** Map of input ports for this resource */ protected Hashtable<String, Servant> portServants; /** Map of input ports for this resource */ protected Hashtable<String, org.omg.CORBA.Object> ports; /** Map of native ports for this resource */ protected Hashtable<String, omnijni.Servant> nativePorts; /** Map of properties for this resource */ protected Hashtable<String, IProperty> propSet; /** Map of port descriptions for this resource */ protected HashMap<String, String> portDescriptions; /** flag if we're started */ protected volatile boolean _started = false; /** flag if we're released */ protected boolean disposed = false; /** flag if we're already initialized */ protected boolean initialized = false; /** the processing thread, if any */ protected Thread processingThread; /** port to be used to output property changes */ protected PropertyEventSupplier propertyChangePort; protected String softwareProfile; /** flag for whether initializeProperties has been called */ private boolean _propertiesInitialized = false; protected Hashtable< String, PropertyChangeRec > _propChangeRegistry; protected PropertyChangeProcessor _propChangeProcessor; protected Thread _propChangeThread; /** * Constructor intended to be used by start_component. */ public Resource() { // configure Logging resource context super( logger, Resource.class.getName() ); this.compId = ""; this.compName = ""; this._started = false; this.propertyChangePort = null; this.ports = new Hashtable<String, org.omg.CORBA.Object>(); this.portServants = new Hashtable<String, Servant>(); this.portObjects = new Hashtable<String, Object>(); this.nativePorts = new Hashtable<String, omnijni.Servant>(); this.propSet = new Hashtable<String, IProperty>(); this.portDescriptions = new HashMap<String, String>(); this._propChangeRegistry = new Hashtable< String, PropertyChangeRec >(); this._propChangeProcessor = new PropertyChangeProcessor(this); } public void addProperty(IProperty prop) { this.propSet.put(prop.getId(), prop); } public void addPort(String name, Object object) { this.portObjects.put(name, object); this.portServants.put(name, (Servant)object); } protected void addPort(String name, omnijni.Servant servant) { this.nativePorts.put(name, servant); } public void addPort(String name, String description, Object object) { this.portDescriptions.put(name, description); addPort(name, object); } protected void addPort(String name, String description, omnijni.Servant servant) { this.portDescriptions.put(name, description); addPort(name, servant); } /** * Start processing for any ports that support it. */ protected void startPorts() { for (StartablePort port : getStartablePorts()) { port.startPort(); } } /** * Stop processing for any ports that support it. If there are any calls on * the port that are blocking, this should cause them to return immediately. */ protected void stopPorts() { for (StartablePort port : getStartablePorts()) { port.stopPort(); } } /** * Returns a list of the registered ports that support the StartablePort * interface. */ private List<StartablePort> getStartablePorts() { List<StartablePort> startablePorts = new ArrayList<StartablePort>(); for (Servant servant : this.portServants.values()) { if (servant instanceof StartablePort) { startablePorts.add((StartablePort) servant); } } for (omnijni.Servant servant : this.nativePorts.values()) { if (servant instanceof StartablePort) { startablePorts.add((StartablePort) servant); } } return startablePorts; } /** * Default Constructor that automatically sets parameters for the Sun ORB * and the JacORB ORB. * * @param compId Name of this resource * @param orb the ORB to use * @throws WrongPolicy * @throws ServantNotActive */ public Resource(final String compId, final String compName, final ORB orb, final POA poa) throws ServantNotActive, WrongPolicy { this(); this.setup(compId, compName, orb, poa); } /** * {@inheritDoc} */ public String identifier() { return this.compId; } public String softwareProfile() { if (softwareProfile == null) { return ""; } else { return softwareProfile; } } /** * {@inheritDoc} */ public boolean started() { return this._started; } public String getName() { return this.compName; } /* METHODS EXPECTED TO BE IMPLEMENTED BY THE USER */ /** * REDHAWK constructor */ public void constructor() { } /** * {@inheritDoc} */ public void initialize() throws InitializeError { logger.trace("initialize()"); if (!initialized) { this.ports.clear(); for (Map.Entry<String, Servant> me : this.portServants.entrySet()) { org.omg.CORBA.Object obj = activateObject(me.getValue()); this.ports.put(me.getKey(), obj); } initialized = true; try { this.constructor(); } catch (final Throwable exc) { final String message = exc.getMessage(); logger.error("initialize(): " + message); throw new InitializeError(new String[]{message}); } } } /** * {@inheritDoc} */ public void start() throws StartError { // While we are starting or stopping don't let anything else occur logger.trace("start()"); synchronized (this) { startPorts(); this._started = true; if (processingThread == null) { processingThread = new Thread(this); processingThread.setDaemon(true); processingThread.start(); } } } /** * {@inheritDoc} */ public void stop() throws StopError { logger.trace("stop()"); synchronized (this) { if (processingThread != null) { stopPorts(); this._started = false; try { processingThread.interrupt(); processingThread.join(1000); if (processingThread.isAlive()) { logger.error("Error stopping processing thread"); throw new StopError(CF.ErrorNumberType.CF_NOTSET, "Error stopping processing thread"); } else { processingThread = null; } } catch (InterruptedException e) { logger.error("Error stopping processing thread", e); throw new StopError(CF.ErrorNumberType.CF_NOTSET, "Error stopping processing thread due to: " + e.toString()); } } } } /** * {@inheritDoc} */ public void runTest(final int testid, final PropertiesHolder testValues) throws UnknownTest, UnknownProperties { logger.trace("runTest()"); } /* BASE CLASS METHODS */ public void releaseObject() throws ReleaseError { logger.trace("releaseObject()"); try { this.stopPropertyChangeMonitor(); this.stop(); } catch (StopError e1) { logger.error("Failed to stop during release", e1); } // These loops deactivate the port objects so that they can be destroyed without incident synchronized (this) { try { // Deactivate all native ports; this will delete the omniORB servant. for (final omnijni.Servant s : this.nativePorts.values()) { s._deactivate(); } this.nativePorts.clear(); for (final org.omg.CORBA.Object p : this.ports.values()) { this.poa.deactivate_object(this.poa.reference_to_id(p)); } // multi-stage destruction for the ports is necessary to account for the initial memory // allocation and the creation of the different maps // Might have to do something different here? this.ports.clear(); this.poa.deactivate_object(this.poa.reference_to_id(resource)); } catch (final Exception e) { throw new ReleaseError(new String[] {e.toString()}); } disposed = true; notifyAll(); } } public Object getPortObject(final String name) throws UnknownPort { // the mapping of ports assumes that port names are unique to the component // the Ports_var maps are kept different (they could be made into one) // because it's less confusing this way Object p = this.portObjects.get(name); if (p != null) { return p; } throw new UnknownPort("Unknown port: " + name); } public org.omg.CORBA.Object getPort(final String name) throws UnknownPort { // the mapping of ports assumes that port names are unique to the component // the Ports_var maps are kept different (they could be made into one) // because it's less confusing this way logger.trace("getPort(" + name + ")"); if (this.nativePorts.containsKey(name)) { return this.nativePorts.get(name)._this_object(getOrb()); } org.omg.CORBA.Object p = this.ports.get(name); if (p != null) { return p; } throw new UnknownPort("Unknown port: " + name); } public void initializeProperties(final DataType[] ctorProperties) throws AlreadyInitialized, InvalidConfiguration, PartialConfiguration { logger.trace("initializeProperties() - star "); // Disallow multiple calls if (this._propertiesInitialized) { throw new AlreadyInitialized(); } this._propertiesInitialized = true; // Ensure there's something to do if (ctorProperties.length == 0) { return; } final ArrayList<DataType> invalidProperties = new ArrayList<DataType>(); for (final DataType dt : ctorProperties) { // Look up the property and ensure it is configurable final IProperty prop = this.propSet.get(dt.id); if (prop == null) { invalidProperties.add(dt); continue; } try { // See if the value has changed if (AnyUtils.compareAnys(prop.toAny(), dt.value, "ne")) { // Update the value on the property, which may trigger a // callback. prop.configureNoCallbacks(dt.value); } logger.trace("Construct property: " + prop); } catch (Throwable t) { logger.error("Unable to construct property " + dt.id + ": " + t.getMessage()); invalidProperties.add(dt); } } if (invalidProperties.size() == ctorProperties.length) { throw new InvalidConfiguration("Error constructing component", invalidProperties.toArray(new DataType[0])); } else if (invalidProperties.size() > 0) { throw new PartialConfiguration(invalidProperties.toArray(new DataType[0])); } logger.trace("initializeProperties() - end"); } public PortInfoType[] getPortSet () { final ArrayList<PortInfoType> ports = new ArrayList<PortInfoType>(); for (String name : this.nativePorts.keySet()) { PortInfoType info = new PortInfoType(); try { info.obj_ptr = getPort(name); } catch (UnknownPort ex) { continue; } info.name = name; omnijni.Servant port = this.nativePorts.get(name); if (port instanceof PortBase) { PortBase cast = (PortBase)port; info.repid = cast.getRepid(); info.direction = cast.getDirection(); } else { info.repid = "IDL:CORBA/Object:1.0"; info.direction = "direction"; } if (this.portDescriptions.containsKey(name)) { info.description = this.portDescriptions.get(name); } else { info.description = ""; } ports.add(info); } for (String name : this.portServants.keySet()) { PortInfoType info = new PortInfoType(); try { info.obj_ptr = getPort(name); } catch (UnknownPort ex) { continue; } info.name = name; Servant port = this.portServants.get(name); if (port instanceof PortBase) { PortBase cast = (PortBase)port; info.repid = cast.getRepid(); info.direction = cast.getDirection(); } else { info.repid = "IDL:CORBA/Object:1.0"; info.direction = "direction"; } if (this.portDescriptions.containsKey(name)) { info.description = this.portDescriptions.get(name); } else { info.description = ""; } ports.add(info); } return ports.toArray(new PortInfoType[0]); } /** * {@inheritDoc} */ public void configure(final DataType[] configProperties) throws InvalidConfiguration, PartialConfiguration { logger.trace("configure()"); // Ensure there's something to do if (configProperties.length == 0) { return; } final ArrayList<DataType> invalidProperties = new ArrayList<DataType>(); for (final DataType dt : configProperties) { // Look up the property and ensure it is configurable final IProperty prop = this.propSet.get(dt.id); if ((prop == null) || !prop.isConfigurable()) { invalidProperties.add(dt); continue; } try { Any value_before = prop.toAny(); // Update the value on the property, which may trigger a // callback. prop.configure(dt.value); if (AnyUtils.compareAnys(value_before, prop.toAny(), "eq")) { logger.debug("Value has not changed on configure for property " + dt.id + ". Not triggering callback"); } else { // The property value changed. // Check to see if this property should issue property change // events and a port is registered. if (prop.isEventable() && (this.propertyChangePort != null)) { this.propertyChangePort.sendPropertyEvent(prop.getId()); } } logger.trace("Configured property: " + prop); } catch (Throwable t) { logger.error("Unable to configure property " + dt.id + ": " + t.getMessage()); invalidProperties.add(dt); } } if (invalidProperties.size() == configProperties.length) { throw new InvalidConfiguration("Error configuring component", invalidProperties.toArray(new DataType[0])); } else if (invalidProperties.size() > 0) { throw new PartialConfiguration(invalidProperties.toArray(new DataType[0])); } } String _propertyQueryTimestamp = "QUERY_TIMESTAMP"; public CF.UTCTime _makeTime(final short status, final double wsec, final double fsec) { CF.UTCTime _time = new CF.UTCTime(status, wsec, fsec); if (status == -1) { long tmp_time = System.currentTimeMillis(); _time.tcstatus = 1; _time.twsec = tmp_time /1000; _time.tfsec = (tmp_time % 1000)/1000.0; } return _time; } /** * {@inheritDoc} */ public void query(final PropertiesHolder configProperties) throws UnknownProperties { logger.trace("query()"); // For queries of zero length, return all id/value pairs in propertySet if (configProperties.value.length == 0) { final ArrayList<DataType> props = new ArrayList<DataType>(this.propSet.size()); for (final IProperty prop : this.propSet.values()) { logger.trace("Querying property: " + prop); if (prop.isQueryable()) { if (prop instanceof StructProperty) { Any structAny = ORB.init().create_any(); final ArrayList<DataType> structProps = new ArrayList<DataType>(); StructDef def = (StructDef)((StructProperty)prop).getValue(); for (final IProperty p : def.getElements()) { if (p.isSet()) { structProps.add(new DataType(p.getId(), p.toAny())); } } PropertiesHelper.insert(structAny, structProps.toArray(new DataType[structProps.size()])); props.add(new DataType(prop.getId(), structAny)); } else { props.add(new DataType(prop.getId(), prop.toAny())); } } } /*final Any anytime = ORB.init().create_any(); CF.UTCTimeHelper.insert(anytime, this._makeTime((short)-1,0,0)); props.add(new DataType(_propertyQueryTimestamp, anytime));*/ configProperties.value = props.toArray(new DataType[props.size()]); return; } // For queries of length > 0, return all requested pairs in propertySet final ArrayList<DataType> validProperties = new ArrayList<DataType>(); final ArrayList<DataType> invalidProperties = new ArrayList<DataType>(); // Return values for valid queries in the same order as requested for (final DataType dt : configProperties.value) { // Look up the property and ensure it is queryable if (dt.id.equals(_propertyQueryTimestamp)) { final Any anytime = ORB.init().create_any(); CF.UTCTimeHelper.insert(anytime, this._makeTime((short)-1,0,0)); validProperties.add(new DataType(_propertyQueryTimestamp, anytime)); continue; } final IProperty prop = this.propSet.get(dt.id); if ((prop != null) && prop.isQueryable()) { if (prop instanceof StructProperty) { Any structAny = ORB.init().create_any(); final ArrayList<DataType> structProps = new ArrayList<DataType>(); StructDef def = (StructDef)((StructProperty)prop).getValue(); for (final IProperty p : def.getElements()) { if (p.isSet()) { structProps.add(new DataType(p.getId(), p.toAny())); } } PropertiesHelper.insert(structAny, structProps.toArray(new DataType[structProps.size()])); validProperties.add(new DataType(prop.getId(), structAny)); } else { validProperties.add(new DataType(prop.getId(), prop.toAny())); } } else { invalidProperties.add(dt); } } // Store query results back in holder configProperties.value = validProperties.toArray(new DataType[validProperties.size()]); if (invalidProperties.size() > 0) { throw new UnknownProperties(invalidProperties.toArray(new DataType[invalidProperties.size()])); } } /** * {@inheritDoc} */ public String registerPropertyListener(final org.omg.CORBA.Object listener, String[] prop_ids, float interval) throws CF.UnknownProperties, CF.InvalidObjectReference { logger.trace("registerPropertyListener - start "); ArrayList<String> pids = new ArrayList<String>(); final ArrayList<DataType> invalidProperties = new ArrayList<DataType>(); String reg_id; synchronized(this) { // For queries of zero length, return all id/value pairs in propertySet if (prop_ids.length == 0) { logger.trace("registering all properties..."); for (final IProperty prop : this.propSet.values()) { if (prop.isQueryable()) { logger.debug("..... property:" + prop.getId()); pids.add(prop.getId()); } } } else { // For queries of length > 0, return all requested pairs in propertySet logger.trace("registering fixed property: N:" + prop_ids.length); // Return values for valid queries in the same order as requested for (final String id : prop_ids) { // Look up the property and ensure it is queryable final IProperty prop = this.propSet.get(id); if ((prop != null) && prop.isQueryable()) { logger.debug("..... property:" + id); pids.add(prop.getId()); } else { DataType dt = new DataType(id, null); invalidProperties.add(dt); } } } if (invalidProperties.size() > 0) { throw new UnknownProperties(invalidProperties.toArray(new DataType[invalidProperties.size()])); } logger.trace("PropertyChangeListener: register N properties: " + pids.size()); PropertyChangeRec prec = new PropertyChangeRec( listener, compId, interval, pids, this.propSet ); // check if our listener is valid if ( prec.pcl == null ) { logger.error("PropertyChangeListener: caller provided invalid listener interface "); prec = null; throw new CF.InvalidObjectReference(); } // Add the registry record to our map logger.debug("registerPropertyListener REGISTERING id-s/regid: " + pids.size() + "/" + prec.regId ); this._propChangeRegistry.put( prec.regId, prec ); reg_id = prec.regId; // start monitoring thread if not started if ( this._propChangeThread == null ) { logger.debug("registerPropertyListener - First registration ... starting monitoring thread "); this._propChangeProcessor.start(); this._propChangeThread = new Thread( this._propChangeProcessor ); this._propChangeThread.start(); } } logger.trace("registerPropertyListener - end"); return reg_id; } public void unregisterPropertyListener(final String reg_id) throws CF.InvalidIdentifier { logger.trace("unregisterPropertyListener - start "); synchronized(this) { PropertyChangeRec prec = this._propChangeRegistry.get(reg_id); if ( prec != null ) { logger.trace("unregisterPropertyListener - Remove registration " +reg_id ); for ( String id : prec.props.keySet() ) { final IProperty prop = this.propSet.get(id); if ( prop != null ) { @SuppressWarnings("unchecked") final PropertyListener<Object> pcl = prec.props.get(id); if ( pcl != null ) { prop.removeObjectListener( pcl ); } } } this._propChangeRegistry.remove(reg_id); logger.debug("unregisterPropertyListener - UNREGISTER REG-ID:" + reg_id ); if ( this._propChangeRegistry.size() == 0 ) { logger.debug("unregisterPropertyListener - No more registrants... stopping thread "); this.stopPropertyChangeMonitor(); this._propChangeThread=null; } } else { throw new CF.InvalidIdentifier(); } } return; } public void stopPropertyChangeMonitor() { if ( _propChangeProcessor != null ) { _propChangeProcessor.stop(); try { if ( _propChangeThread != null ) { _propChangeThread.join(); } } catch( InterruptedException ex ) { } } } /** * Perform reporting portion of PropertyChangeListeners that are registered with this resource. * After the requested interval has expired report and changes since the last reporting cycle. * Notifications are sent out via EventChannel or implementors of PropertyChangeListern interface * is not told to release. * * @return NOOP informs calling thread controller to delay before next cycle */ protected int _propertyChangeServiceFunction() { logger.trace("_propertyChangeServiceFunction ... start "); long delay=0; synchronized(this) { // for each registration record for ( PropertyChangeRec prec : _propChangeRegistry.values() ) { // get current time stamp.... and duration since last check long now = System.currentTimeMillis(); long dur = prec.expiration - now; logger.debug( "Resource::_propertyChangeServiceFunction ... reg_id/interval :" + prec.regId + "/" + prec.reportInterval + " expiration=" + dur ); // determine if time has expired if ( dur <= 0 ) { // For queries of length > 0, return all requested pairs in propertySet final ArrayList<DataType> rpt_props = new ArrayList<DataType>(); // check all registered properties for changes for (Map.Entry<String, PCL_Callback> iter : prec.props.entrySet() ) { String pid = iter.getKey(); PCL_Callback pcb = iter.getValue(); logger.trace(" Check Property/Set " + pid + "/" + pcb.isSet() ); // check if property changed if ( pcb.isSet() == true ) { final IProperty prop = this.propSet.get(pid); if (prop != null) { rpt_props.add(new DataType(pid, prop.toAny())); } } // reset change indicator for next reporting cycle pcb.reset(); } // publish changes to listener if ( rpt_props.size() > 0 && prec.pcl != null ) { logger.debug(" Notify PropertyChangeListener ...size/reg :" + rpt_props.size() + "/" + prec.regId ); DataType [] rprops = rpt_props.toArray( new DataType[ rpt_props.size() ] ); if ( prec.pcl.notify( prec, rprops ) != 0 ) { logger.error("Publishing changes to PropertyChangeListener FAILED, reg_id:" + prec.regId ); // probably should mark for removal... if last one then stop the thread... } } // reset time indicator prec.expiration = System.currentTimeMillis() + prec.reportInterval; dur = prec.reportInterval; } // find smallest increment of time to wait if ( delay == 0 ) { delay=dur; } logger.trace( " Test for delay/duration (millisecs) ... :" + delay + "/" + dur ); if ( dur > 0 ) { delay = Math.min( delay, dur ); } logger.trace( " Minimum delay (millisecs) ... :" + delay ); } // end synchronized if ( delay > 0 ) { logger.debug( "....Set monitoring thread delay (millisecs) ... :" + delay ); _propChangeProcessor.setThreadDelay( delay/1000.0f ); } } logger.trace("_propertyChangeServiceFunction ... end "); return ThreadedComponent.NOOP; } /** * This returns true if the component constructor has run and the component * is not told to release. * * @deprecated use started instead * @return true if the component is started */ public boolean isRunning() { return this._started; } /** * Register whichever port is to be used to issue property changes */ public void registerPropertyChangePort(final PropertyEventSupplier _propertyChangePort) { this.propertyChangePort = _propertyChangePort; } protected boolean isDisposed() { return this.disposed; } /** * This returns the CORBA ORB used by the component * * @return the ORB in use */ public org.omg.CORBA.ORB getOrb() { return this.orb; } /** * This returns the RootPOA manager for the ORB in use * * @return the POA manager */ public POA getPoa() { return this.poa; } /** * This function is used by derived classes to set a pointer to the * Domain Manager and Application * * @param ApplicationRegistrarIOR IOR to either the Application Registrar or Naming Context */ public void setAdditionalParameters(final String ApplicationRegistrarIOR, String nic) { final org.omg.CORBA.Object obj = this.orb.string_to_object(ApplicationRegistrarIOR); ApplicationRegistrar appReg = null; try { appReg = ApplicationRegistrarHelper.narrow(obj); } catch (Exception e) {} if (appReg != null) { if (appReg.domMgr()!=null) { this._domMgr = new DomainManagerContainer(appReg.domMgr()); this.logger.info("setAdditionalParameters domain: " + this._domMgr.getRef().name() ); } if ( this._domMgr != null ) { try { this._ecm = org.ossie.events.Manager.GetManager(this); }catch( org.ossie.events.Manager.OperationFailed e){ logger.warn("Unable to resolve EventChannelManager"); } } } } public DomainManagerContainer getDomainManager() { return this._domMgr; } public org.ossie.events.Manager getEventChannelManager() { return this._ecm; } public void saveLoggingContext( String logcfg_url, int oldstyle_loglevel, logging.ResourceCtx ctx ) { super.saveLoggingContext( logcfg_url, oldstyle_loglevel, ctx, this.getEventChannelManager () ); } public void setNewLoggingListener( LoggingListener newListener ) { super.setNewLoggingListener( newListener ); } /** * This function explicitly activates the given Servant. * * @param s the Servant to activate * @return the activated CORBA Object */ protected org.omg.CORBA.Object activateObject(final Servant s) { try { final byte[] oid = this.poa.activate_object(s); return this.poa.id_to_reference(oid); } catch (final ServantAlreadyActive e) { // PASS } catch (final WrongPolicy e) { // PASS } catch (final ObjectNotActive e) { // PASS } return null; } /** * Initializes properties via the execparams. * * @param execparams */ protected void initializeProperties(Map<String, String> execparams) { for (Map.Entry<String, String> execparam : execparams.entrySet()) { IProperty prop = propSet.get(execparam.getKey()); if (prop != null) { prop.fromString(execparam.getValue()); } } } /** * Protected initialize intended only to be used by start_component. * * @deprecated use {@link setup(String, String, String, ORB, POA)} * @param compId * @param orb * @throws WrongPolicy * @throws ServantNotActive */ protected CF.Resource setup(final String compId, final String compName, final ORB orb, final POA poa) throws ServantNotActive, WrongPolicy { this.compId = compId; this.compName = compName; this.orb = orb; this.poa = poa; ResourcePOATie tie = new ResourcePOATie(this, poa); tie._this(orb); resource = ResourceHelper.narrow(poa.servant_to_reference((Servant)tie)); return resource; } /** * Protected initialize intended only to be used by start_component. * * @param compId * @param compName * @param softwareProfile * @param orb * @param poa * @throws WrongPolicy * @throws ServantNotActive */ protected CF.Resource setup(final String compId, final String compName, final String softwareProfile, final ORB orb, final POA poa) throws ServantNotActive, WrongPolicy { CF.Resource result = this.setup(compId, compName, orb, poa); this.softwareProfile = softwareProfile; return result; } /** * Parse the set of SCA execparam arguments into a Map * * @param args as passed in from the command line * @return a map of arg/value pairs */ protected static Map<String, String> parseArgs(String[] args) { logger.trace("Starting with execparams: " + Arrays.toString(args)); Map<String, String> result = new Hashtable<String, String>(); for (int i=0; i < (args.length - 1); i = i +2) { result.put(args[i], args[i+1]); } logger.trace("Starting with execparams: " + result); return result; } /** * Start-up function to be used from a main() function. * * @param clazz * @param args * @param builtInORB * @param fragSize * @param bufSize * @throws InstantiationException * @throws IllegalAccessException * @throws InvalidObjectReference * @throws org.omg.CosNaming.NamingContextPackage.InvalidName * @throws CannotProceed * @throws NotFound * @throws WrongPolicy * @throws ServantNotActive */ public static void start_component(final Class<? extends Resource> clazz, final String[] args, final boolean builtInORB, final int fragSize, final int bufSize) throws InstantiationException, IllegalAccessException, InvalidObjectReference, NotFound, CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName, ServantNotActive, WrongPolicy { final Properties props = new Properties(); if (!builtInORB) { props.put("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB"); props.put("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton"); props.put("jacorb.fragment_size", Integer.toString(fragSize)); props.put("jacorb.outbuf_size", Integer.toString(bufSize)); props.put("jacorb.maxManagedBufSize", "23"); } else { props.put("com.sun.CORBA.giop.ORBFragmentSize", Integer.toString(fragSize)); props.put("com.sun.CORBA.giop.ORBBufferSize", Integer.toString(bufSize)); } start_component(clazz, args, props); } /** * Start-up function to be used from a main() function. * * @param clazz * @param args * @param builtInORB * @param fragSize * @param bufSize * @throws InstantiationException * @throws IllegalAccessException * @throws InvalidObjectReference * @throws org.omg.CosNaming.NamingContextPackage.InvalidName * @throws CannotProceed * @throws NotFound * @throws WrongPolicy * @throws ServantNotActive */ public static void start_component(final Class<? extends Resource> clazz, final String[] args, final Properties props) throws InstantiationException, IllegalAccessException, InvalidObjectReference, NotFound, CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName, ServantNotActive, WrongPolicy { if (args.length == 1) { if (args[0].equals("-i")) { System.out.println("Interactive mode (-i) no longer supported. Please use the sandbox to run Components/Devices/Services outside the scope of a Domain"); System.exit(-1); } } // initialize library's ORB reference final org.omg.CORBA.ORB orb = org.ossie.corba.utils.Init( args, props ); final POA rootpoa = org.ossie.corba.utils.RootPOA(); Map<String, String> execparams = parseArgs(args); // Configure log4j from the execparams (or use default settings). // TOBERM Resource.configureLogging(execparams, orb); NamingContext nameContext = null; NamingContextExt nameContextExt = null; ApplicationRegistrar applicationRegistrar = null; if (execparams.containsKey("NAMING_CONTEXT_IOR")) { try { final org.omg.CORBA.Object tmp_obj = orb.string_to_object(execparams.get("NAMING_CONTEXT_IOR")); try { applicationRegistrar = ApplicationRegistrarHelper.narrow(tmp_obj); } catch (Exception e) {} nameContext = NamingContextHelper.narrow(tmp_obj); try { nameContextExt = NamingContextExtHelper.narrow(tmp_obj); } catch (Exception e) { // the application registrar inherits from naming context, not naming context ext } } catch (Exception e) { System.out.println(e); } } String identifier = null; if (execparams.containsKey("COMPONENT_IDENTIFIER")) { identifier = execparams.get("COMPONENT_IDENTIFIER"); } String nameBinding = null; if (execparams.containsKey("NAME_BINDING")) { nameBinding = execparams.get("NAME_BINDING"); } String dom_path = ""; if (execparams.containsKey("DOM_PATH")) { dom_path = execparams.get("DOM_PATH"); } String logcfg_uri = ""; if (execparams.containsKey("LOGGING_CONFIG_URI")) { logcfg_uri = execparams.get("LOGGING_CONFIG_URI"); } int debugLevel = -1; // use logging config properties for level if (execparams.containsKey("DEBUG_LEVEL")) { debugLevel = Integer.parseInt(execparams.get("DEBUG_LEVEL")); } if ( debugLevel > 3 ) { System.out.println("Resource Args: " ); System.out.println(" NAME_BINDING:"+ nameBinding ); System.out.println(" COMPONENT_IDENTIFIER:"+ identifier ); System.out.println(" NAMING_CONTEXT_IOR:"+ nameContext ); System.out.println(" DOM_PATH:"+ dom_path ); System.out.println(" LOG_CONFIG_URI:"+ logcfg_uri ); System.out.println(" DEBUG_LEVEL:"+ debugLevel ); } String profile = ""; if (execparams.containsKey("PROFILE_NAME")) { profile = execparams.get("PROFILE_NAME"); } if ((nameContext == null) || (nameBinding == null)) { System.out.println("usage: "+clazz+" [options] [execparams]\n"); System.out.println("The set of execparams is defined in the .prf for the component"); System.out.println("They are provided as arguments pairs ID VALUE, for example:"); System.out.println(" "+clazz+" INT_PARAM 5 STR_PARAM ABCDED\n"); System.exit(-1); } logging.ComponentCtx ctx = new logging.ComponentCtx( nameBinding, identifier, dom_path ); logging.Configure( logcfg_uri, debugLevel, ctx ); final Resource resource_i = clazz.newInstance(); final CF.Resource resource = resource_i.setup(identifier, nameBinding, profile, orb, rootpoa); String nic = ""; if (execparams.containsKey("NIC")) { nic = execparams.get("NIC"); } resource_i.setAdditionalParameters(execparams.get("NAMING_CONTEXT_IOR"), nic); resource_i.initializeProperties(execparams); // save logging context used by the resource... resource_i.saveLoggingContext( logcfg_uri, debugLevel, ctx ); if ((nameContext != null) && (nameBinding != null)) { if (applicationRegistrar != null) { try { applicationRegistrar.registerComponent(nameBinding, resource); } catch (Exception e) { System.out.println("Unable to register "+nameBinding); System.out.println(e); } } else { String[] names = nameBinding.split("/"); ArrayList<org.omg.CosNaming.NameComponent> name_to_bind = new ArrayList<org.omg.CosNaming.NameComponent>(); for (String name : names) { org.omg.CosNaming.NameComponent Cos_name = new org.omg.CosNaming.NameComponent(name, ""); name_to_bind.add(Cos_name); } org.omg.CosNaming.NameComponent[] name_binding_array = new org.omg.CosNaming.NameComponent[0]; nameContext.rebind(name_to_bind.toArray(name_binding_array), resource); } } else { // Print out the IOR so that someone can debug against the component System.out.println("The IOR for your component is:\n" + orb.object_to_string(resource)); } // Create a thread that watches for the resource to be deactivated Thread shutdownWatcher = new Thread(new Runnable() { public void run() { resource_i.waitDisposed(); // On slow VMs, shutting down the ORB immediately after // releaseObject() sometimes leads to a CORBA.COMM_FAILURE // exception being thrown to the caller, presumably because // it's still closing out the request. A small delay before // shutting down the ORB (1 usec) appears to reduce the // likelihood of that happening to, effectively, zero. try { Thread.sleep(0, 1000); } catch (final InterruptedException exc) { } shutdownORB(orb); } }); shutdownWatcher.start(); orb.run(); logger.trace("Waiting for shutdown watcher to join"); try { shutdownWatcher.join(); } catch (InterruptedException e) { // PASS } // Destroy the ORB, otherwise the JVM shutdown will take an unusually // long time (~300ms). orb.destroy(); logger.debug("Goodbye!"); } protected void waitDisposed() { synchronized(this) { while (!this.isDisposed()) { try { this.wait(); } catch (InterruptedException e) { // PASS } } } } /** * Configure log4j for use in a component. The order of preference for settings is: * * 1. LOGGING_CONFIG_URI execparam * 2. DEBUG_LEVEL execparam * 3. Default debug level (INFO) * * @deprecated use {@link logging#Configure(String, int)} * @param execparams Map of component execparam values * @param orb CORBA ORB instance for contacting SCA FileSystem (if LOGGING_CONFIG_URI is an SCA URI) */ protected static void configureLogging(final Map<String, String> execparams, final org.omg.CORBA.ORB orb) { // Sets up the logging String loggingConfigURI = null; if (execparams.containsKey("LOGGING_CONFIG_URI")) { loggingConfigURI = execparams.get("LOGGING_CONFIG_URI"); if (loggingConfigURI.indexOf("file://") != -1){ int startIndex = loggingConfigURI.indexOf("file://") + 7; PropertyConfigurator.configure(loggingConfigURI.substring(startIndex)); }else if (loggingConfigURI.indexOf("sca:") != -1){ int startIndex = loggingConfigURI.indexOf("sca:") + 4; String localFile = Resource.getLogConfig(loggingConfigURI.substring(startIndex), orb); File testLocalFile = new File(localFile); if (localFile.length() > 0 && testLocalFile.exists()){ PropertyConfigurator.configure(localFile); } } } else { int debugLevel = 3; // Default level is INFO if (execparams.containsKey("DEBUG_LEVEL")) { debugLevel = Integer.parseInt(execparams.get("DEBUG_LEVEL")); } logging.ConfigureDefault(); logging.SetLevel( null, debugLevel ); } } /** * This function returns the filename of the local logging configuration file given an SCA FileSystem logging file. * * @param uri string containing SCA File System filename for logging configuration file * @param orb CORBA ORB instance for contacting SCA FileSystem * @return the string reprenting the local logging configuration filename */ protected static String getLogConfig(String uri, org.omg.CORBA.ORB orb) { String localPath = ""; int fsPos = uri.indexOf("?fs="); if (fsPos == -1) { return localPath; } String IOR = uri.substring(fsPos + 4); org.omg.CORBA.Object obj = orb.string_to_object(IOR); if (obj == null) { return localPath; } CF.FileSystem fileSystem = CF.FileSystemHelper.narrow(obj); if (fileSystem == null) { return localPath; } String remotePath = uri.substring(0, fsPos); CF.OctetSequenceHolder data = new CF.OctetSequenceHolder (); try { CF.File remoteFile = fileSystem.open(remotePath, true); int size = remoteFile.sizeOf(); remoteFile.read(data, size); String tempPath = remotePath; int slashPos = remotePath.lastIndexOf('/'); if (slashPos != -1) { tempPath = tempPath.substring(slashPos + 1); } FileOutputStream localFile = new FileOutputStream(tempPath); localFile.write(data.value); localPath = tempPath; localFile.close(); return localPath; } catch (Exception e){ return localPath; } } /** * This function returns the filename of the local logging configuration file given an SCA FileSystem logging file. * * @param uri string containing SCA File System filename for logging configuration file * @return the string reprenting the local logging configuration filename */ protected String getLogConfig(String uri) { return Resource.getLogConfig(uri, this.orb); } protected static void shutdownORB(final org.omg.CORBA.ORB orb) { // Disable the default ORB logger to avoid dumping warnings // on shutdown that are unavoidable and otherwise harmless disableCORBALogging(); logger.trace("Shutting down orb"); orb.shutdown(true); } private static void disableCORBALogging() { java.util.logging.Logger.getLogger("javax.enterprise.resource.corba").setLevel(java.util.logging.Level.OFF); } }