package org.jacorb.orb; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.jacorb.config.Configurable; import org.jacorb.config.Configuration; import org.jacorb.config.ConfigurationException; import org.omg.CONV_FRAME.CodeSetComponentHelper; import org.omg.CONV_FRAME.CodeSetComponentInfo; import org.omg.CONV_FRAME.CodeSetComponentInfoHelper; import org.omg.IOP.TaggedComponent; import org.omg.IOP.TaggedComponentSeqHelper; /** * Represents a list of tagged components from an IOR, along with some * generic methods to find and access individual components. * <p> * @author Andre Spiegel */ public class TaggedComponentList implements Cloneable { private TaggedComponent[] components = null; /** * Constructs a TaggedComponentList object from a CDR representation * of an array of tagged components. */ public TaggedComponentList (org.omg.CORBA.portable.InputStream in) { components = TaggedComponentSeqHelper.read (in); } /** * Constructs a TaggedComponentList from a CDR encapsulation of * an array of tagged components. */ public TaggedComponentList (byte[] data) { CDRInputStream in = new CDRInputStream (data); in.openEncapsulatedArray(); components = TaggedComponentSeqHelper.read (in); } /** * Constructs a new, empty TaggedComponentList. */ public TaggedComponentList() { components = new TaggedComponent[0]; } public int size() { return components.length; } public boolean isEmpty() { return components.length == 0; } public TaggedComponent get (int index) { return components[index]; } public Object clone() throws CloneNotSupportedException { TaggedComponentList result = (TaggedComponentList)super.clone(); result.components = new TaggedComponent[this.components.length]; for (int i=0; i<this.components.length; i++) { result.components[i] = new TaggedComponent ( this.components[i].tag, new byte [this.components[i].component_data.length] ); System.arraycopy (this.components[i].component_data, 0, result.components[i].component_data, 0, this.components[i].component_data.length); } return result; } public TaggedComponent[] asArray() { return components; } /** * Adds a tagged component to this list. The component's data * is created by marshaling the given data Object using the * write() method of the given helper class. */ public void addComponent (int tag, Object data, Class helper) { try { Method writeMethod = helper.getMethod ( "write", new Class[] { org.omg.CORBA.portable.OutputStream.class, data.getClass() } ); final CDROutputStream out = new CDROutputStream(); try { out.beginEncapsulatedArray(); writeMethod.invoke ( null, new Object[]{ out, data } ); addComponent (tag, out.getBufferCopy()); } finally { out.close(); } } catch (NoSuchMethodException ex) { throw new RuntimeException ("Helper " + helper.getName() + " has no appropriate write() method."); } catch (IllegalAccessException ex) { throw new RuntimeException ("Cannot access write() method of helper " + helper.getName()); } catch (InvocationTargetException ex) { throw new RuntimeException ("Exception while marshaling component data: " + ex.getTargetException()); } } /** * Adds a tagged component to this list. */ public void addComponent (int tag, byte[] data) { addComponent (new TaggedComponent (tag, data)); } /** * Adds a tagged component to this list. */ public void addComponent (TaggedComponent component) { TaggedComponent[] newComponents = new TaggedComponent [components.length + 1]; System.arraycopy (components, 0, newComponents, 0, components.length); newComponents [components.length] = component; components = newComponents; } /** * Adds an entire TaggedComponentList to this list. */ public void addAll (TaggedComponentList other) { TaggedComponent[] newComponents = new TaggedComponent [components.length + other.components.length]; System.arraycopy (components, 0, newComponents, 0, components.length); System.arraycopy (other.components, 0, newComponents, components.length, other.components.length); components = newComponents; } /** * Searches for a component with the given tag in this component list. * If one is found, this method reads the corresponding data with the given * helper class, and returns the resulting object, otherwise returns * null. */ public Object getComponent (int tag, Class helper) { for (int i=0; i < components.length; i++) { if (components[i].tag == tag) { return getComponentData (components[i].component_data, helper); } } return null; } /** * Returns a List of all components with the given tag from this * TaggedComponentList. Each individual component is read with * the given helper class. If no components with the given tag * can be found, an empty list is returned. * * The only caller of this currently is IIOPProfile using a helper * of IIOPAddress. To prevent non-configured IIOPAddresses we configure * them here. */ public List getComponents (Configuration configuration, int tag, Class helper) { List result = new ArrayList(); for (int i=0; i < components.length; i++) { if (components[i].tag == tag) { Object element = getComponentData (components[i].component_data, helper); if (element instanceof Configurable && configuration != null) { try { ((Configurable)element).configure(configuration); } catch( ConfigurationException e ) { throw new org.omg.CORBA.INTERNAL("ConfigurationException: " + e.toString()); } } result.add (element); } } return result; } /** * Uses the given helper class to read a CDR-encapsulated component_data * field from the given byte array, data. */ private Object getComponentData (byte[] data, Class helper) { java.lang.Object result = null; final CDRInputStream in = new CDRInputStream (data); try { in.openEncapsulatedArray(); if (helper == CodeSetComponentInfoHelper.class) { result = new CodeSetComponentInfo(); ((CodeSetComponentInfo)result).ForCharData = (CodeSetComponentHelper.read(in)); ((CodeSetComponentInfo)result).ForWcharData = (CodeSetComponentHelper.read(in)); } else if (helper == ParsedIOR.LongHelper.class) { result = new Integer (in.read_long()); } else if (helper == ParsedIOR.StringHelper.class) { result = in.read_string(); } else { try { Method readMethod = helper.getMethod ("read", new Class[] { org.omg.CORBA.portable.InputStream.class }); result = readMethod.invoke (null, new Object[] { in }); } catch (NoSuchMethodException ex) { throw new RuntimeException ("Helper " + helper.getName() + " has no appropriate read() method."); } catch (IllegalAccessException ex) { throw new RuntimeException ("Cannot access read() method of helper " + helper.getName()); } catch (InvocationTargetException ex) { throw new RuntimeException ("Exception while reading component data: " + ex.getTargetException()); } } } finally { in.close(); } return result; } /** * This function will search and remove the components, whose tag matches * the given tag, from the components list. Removing tags are needed in * the case the the ImR is used. * @param tag */ public void removeComponents (int tag) { // first, count the number of components whose tag matches the given tag. int match_cnt = 0; for (int i=0; i < components.length; i++) { if (components[i].tag == tag) { match_cnt++; } } // nothing more to do if there was no match if (match_cnt == 0) { return; } // create a new TaggedComponent array and move the components whose tag // does not match the given tag. TaggedComponent[] newComponents = new TaggedComponent [components.length - match_cnt]; for (int i=0, n=0; i < components.length; i++) { if (components[i].tag != tag) { newComponents[n++] = components[i]; } } // replace the list components = newComponents; } }