Source for gnu.CORBA.CDR.UnknownExceptionCtxHandler

   1: /* UnknownExceptionCtxHandler.java --
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.CORBA.CDR;
  40: 
  41: import gnu.CORBA.Minor;
  42: import gnu.CORBA.ObjectCreator;
  43: import gnu.CORBA.GIOP.ServiceContext;
  44: 
  45: import org.omg.CORBA.MARSHAL;
  46: import org.omg.CORBA.NO_IMPLEMENT;
  47: import org.omg.CORBA.StringValueHelper;
  48: import org.omg.CORBA.portable.OutputStream;
  49: 
  50: import java.lang.reflect.Constructor;
  51: import java.util.StringTokenizer;
  52: 
  53: import javax.rmi.CORBA.Util;
  54: 
  55: /**
  56:  * Reads the data about an unknown exception from the UnknownExceptionInfo.
  57:  *
  58:  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
  59:  */
  60: public class UnknownExceptionCtxHandler
  61:   extends Vio
  62: {
  63:   /**
  64:    * Encode exception and add its recored to the message service contexts.
  65:    */
  66:   public static ServiceContext[] addExceptionContext(ServiceContext[] current,
  67:     Throwable exception, Object details)
  68:   {
  69:     try
  70:       {
  71:         ServiceContext[] c = new ServiceContext[current.length + 1];
  72:         if (current.length > 0)
  73:           System.arraycopy(current, 0, c, 0, current.length);
  74: 
  75:         BufferedCdrOutput output = new BufferedCdrOutput();
  76: 
  77:         if (details instanceof OutputStream)
  78:           output.setOrb(((OutputStream) output).orb());
  79: 
  80:         if (details instanceof AbstractCdrOutput)
  81:           ((AbstractCdrOutput) details).cloneSettings(output);
  82: 
  83:         write(output, exception);
  84: 
  85:         ServiceContext xc = new ServiceContext();
  86:         xc.context_id = ServiceContext.UnknownExceptionInfo;
  87:         xc.context_data = output.buffer.toByteArray();
  88:         c[current.length] = xc;
  89:         return c;
  90:       }
  91:     catch (Exception ex)
  92:       {
  93:         ex.printStackTrace();
  94:         return current;
  95:       }
  96:   }
  97: 
  98:   /**
  99:    * Write data about unknown exception.
 100:    */
 101:   public static void write(BufferedCdrOutput output, Throwable t)
 102:   {
 103:     t.fillInStackTrace();
 104:     output.write_Value(t);
 105:   }
 106: 
 107:   /**
 108:    * Read the data about an unknown exception from the UnknownExceptionInfo.
 109:    * Following the documentation, this must be just value type, but it seems
 110:    * that in Sun's implementation is is not, as starts from 0x0. For value type,
 111:    * this would be null.
 112:    *
 113:    * TODO Implement reading and writing in Sun format, making Classpath IIOP
 114:    * interoperable with Sun's implementation. Current inmplementation reads and
 115:    * reproduces the exception class type only.
 116:    *
 117:    * @param input the input stream to read the context (orb and other settings
 118:    * are inherited from the main stream that received the message).
 119:    *
 120:    * @param contexts all service contexts that were present in the message.
 121:    *
 122:    * @return the Throwable, extracted from context, on null, if this has failed.
 123:    */
 124:   public static Throwable read(BufferredCdrInput input, ServiceContext[] contexts)
 125:   {
 126:     input.mark(Integer.MAX_VALUE);
 127: 
 128:     int h = input.read_long();
 129:     if (h == 0)
 130:       {
 131:         // This block reads exception info in the Sun specific format.
 132:         // (currently we read the exception name only).
 133:         try
 134:           {
 135:             // We may need to jump back if the value is read via value
 136:             // factory.
 137:             input.mark(512);
 138: 
 139:             int value_tag = input.read_long();
 140:             checkTag(value_tag);
 141: 
 142:             String codebase = null;
 143:             String[] ids = null;
 144:             String id = null;
 145: 
 146:             // Check for the agreed null value.
 147:             if (value_tag == vt_NULL)
 148:               return null;
 149:             else if (value_tag == vt_INDIRECTION)
 150:               return (Throwable) readIndirection(input);
 151:             else
 152:               {
 153:                 // Read the value.
 154:                 if ((value_tag & vf_CODEBASE) != 0)
 155:                   {
 156:                     // The codebase is present. The codebase is a space
 157:                     // separated list of URLs from where the implementing
 158:                     // code can be downloaded.
 159:                     codebase = read_string(input);
 160:                   }
 161: 
 162:                 if ((value_tag & vf_MULTIPLE_IDS) != 0)
 163:                   {
 164:                     // Multiple supported repository ids are present.
 165:                     ids = read_string_array(input);
 166:                   }
 167:                 else if ((value_tag & vf_ID) != 0)
 168:                   {
 169:                     // Single supported repository id is present.
 170:                     id = read_string(input);
 171:                   }
 172:               }
 173: 
 174:             java.lang.Object ox = createInstance(id, ids, codebase);
 175: 
 176:             return (Throwable) ox;
 177:           }
 178:         catch (Exception ex)
 179:           {
 180:             ex.printStackTrace();
 181:             return null;
 182:           }
 183:       }
 184:     else
 185:       {
 186:         input.reset();
 187:         // Read as defined in OMG documentation.
 188:         return (Throwable) input.read_Value();
 189:       }
 190:   }
 191: 
 192:   /**
 193:    * Load exception by name and create the instance. The reason why this is
 194:    * different from Vio is because some exceptions have no parameterless
 195:    * constructor, but have a constructor with the string parameter instead.
 196:    */
 197:   static Object createInstance(String id, String[] ids, String codebase)
 198:   {
 199:     Object o = _createInstance(id, codebase);
 200: 
 201:     if (ids != null)
 202:       for (int i = 0; i < ids.length && o == null; i++)
 203:         o = _createInstance(ids[i], codebase);
 204:     return o;
 205:   }
 206: 
 207:   static Object _createInstance(String id, String codebase)
 208:   {
 209:     if (id == null)
 210:       return null;
 211:     if (id.equals(StringValueHelper.id()))
 212:       return "";
 213:     StringTokenizer st = new StringTokenizer(id, ":");
 214: 
 215:     String prefix = st.nextToken();
 216:     if (prefix.equalsIgnoreCase("IDL"))
 217:       return ObjectCreator.Idl2Object(id);
 218:     else if (prefix.equalsIgnoreCase("RMI"))
 219:       {
 220:         String className = st.nextToken();
 221:         String hashCode = st.nextToken();
 222:         String sid = null;
 223:         if (st.hasMoreElements())
 224:           sid = st.nextToken();
 225: 
 226:         try
 227:           {
 228:             Class objectClass = Util.loadClass(className, codebase,
 229:               Vio.class.getClassLoader());
 230: 
 231:             String rid = ObjectCreator.getRepositoryId(objectClass);
 232: 
 233:             if (!rid.equals(id))
 234:               {
 235:                 // If direct string comparison fails, compare by meaning.
 236:                 StringTokenizer st2 = new StringTokenizer(rid, ":");
 237:                 if (!st2.nextToken().equals("RMI"))
 238:                   throw new InternalError("RMI format expected: '" + rid + "'");
 239:                 if (!st2.nextToken().equals(className))
 240:                   throwIt("Class name mismatch", id, rid, null);
 241: 
 242:                 try
 243:                   {
 244:                     long h1 = Long.parseLong(hashCode, 16);
 245:                     long h2 = Long.parseLong(st2.nextToken(), 16);
 246:                     if (h1 != h2)
 247:                       throwIt("Hashcode mismatch", id, rid, null);
 248: 
 249:                     if (sid != null && st2.hasMoreTokens())
 250:                       {
 251:                         long s1 = Long.parseLong(hashCode, 16);
 252:                         long s2 = Long.parseLong(st2.nextToken(), 16);
 253:                         if (s1 != s2)
 254:                           throwIt("serialVersionUID mismatch", id, rid, null);
 255:                       }
 256:                   }
 257:                 catch (NumberFormatException e)
 258:                   {
 259:                     throwIt("Invalid hashcode or svuid format: ", id, rid, e);
 260:                   }
 261:               }
 262: 
 263:             // Some RemoteExceptions have no public parameterless constructor,
 264:             // but they have constructor taking string as parameter.
 265:             try
 266:               {
 267:                 return objectClass.newInstance();
 268:               }
 269:             catch (Exception ex)
 270:               {
 271:                 // Try instantiate passing string as parameter.
 272:                 Constructor c = objectClass.getConstructor(new Class[] { String.class });
 273:                 return c.newInstance(new Object[] { "<message unavailable>" });
 274:               }
 275:           }
 276:         catch (MARSHAL m)
 277:           {
 278:             m.minor = Minor.Instantiation;
 279:             throw m;
 280:           }
 281:         catch (Exception ex)
 282:           {
 283:             MARSHAL m = new MARSHAL("Unable to instantiate " + id);
 284:             m.minor = Minor.Instantiation;
 285:             m.initCause(ex);
 286:             throw m;
 287:           }
 288:       }
 289:     else
 290:       throw new NO_IMPLEMENT("Unsupported prefix " + prefix + ":");
 291:   }
 292: }