Source for java.beans.XMLEncoder

   1: /* XMLEncoder.java
   2:  Copyright (C) 2004, 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 java.beans;
  40: 
  41: import gnu.java.beans.encoder.ScanEngine;
  42: 
  43: import java.io.OutputStream;
  44: 
  45: /**
  46:  * This class uses the {@link PersistenceDelegate} and {@link Encoder}
  47:  * infrastructure to generate an XML representation of the objects it
  48:  * serializes.
  49:  * 
  50:  * @author Robert Schuster (robertschuster@fsfe.org)
  51:  * @since 1.4
  52:  */
  53: public class XMLEncoder extends Encoder
  54: {
  55:   Object owner;
  56: 
  57:   Exception exception;
  58: 
  59:   ScanEngine scanEngine;
  60: 
  61:   private int accessCounter = 0;
  62: 
  63:   public XMLEncoder(OutputStream os)
  64:   {
  65:     scanEngine = new ScanEngine(os);
  66:   }
  67: 
  68:   public void close()
  69:   {
  70:     if (scanEngine != null)
  71:       {
  72:         scanEngine.close();
  73:         scanEngine = null;
  74:       }
  75:   }
  76: 
  77:   public void flush()
  78:   {
  79:     scanEngine.flush();
  80:   }
  81: 
  82:   public void writeExpression(Expression expr)
  83:   {
  84:     // Implementation note: Why is this method overwritten and nearly exactly
  85:     // reimplemented as in Encoder?
  86:     // The Encoder class can (and should be) subclassed by users outside of the
  87:     // java.beans package. While I have doubts that this is possible from an
  88:     // API design point of view I tried to replicate the Encoder's behavior
  89:     // in the JDK as exactly as possible. This strictness however made it
  90:     // extremely complicated to implement the XMLEncoder's backend. Therefore
  91:     // I decided to copy the Encoder's implementation and make all changes
  92:     // I needed for a succesfull operation of XMLEncoder.
  93:     //
  94:     // The same is true for the writeStatement method.
  95:     
  96:     //  Silently ignore out of bounds calls.
  97:     if (accessCounter <= 0)
  98:       return;
  99:     
 100:     scanEngine.writeExpression(expr);
 101: 
 102: 
 103:     Object target = expr.getTarget();
 104:     Object value = null;
 105:     Object newValue = null;
 106: 
 107:     try
 108:       {
 109:         value = expr.getValue();
 110:       }
 111:     catch (Exception e)
 112:       {
 113:         getExceptionListener().exceptionThrown(e);
 114:         return;
 115:       }
 116:     
 117:     
 118:     newValue = get(value);
 119: 
 120:     if (newValue == null)
 121:       {
 122:         Object newTarget = get(target);
 123:         if (newTarget == null)
 124:           {
 125:             writeObject(target);
 126:             newTarget = get(target);
 127: 
 128:             // May happen if exception was thrown.
 129:             if (newTarget == null)
 130:               {
 131:                 return;
 132:               }
 133:           }
 134: 
 135:         Object[] args = expr.getArguments();
 136:         Object[] newArgs = new Object[args.length];
 137: 
 138:         for (int i = 0; i < args.length; i++)
 139:           {
 140:             newArgs[i] = get(args[i]);
 141:             if (newArgs[i] == null || isImmutableType(args[i].getClass()))
 142:               {
 143:                 writeObject(args[i]);
 144:                 newArgs[i] = get(args[i]);
 145:               }
 146:           }
 147:         
 148:         Expression newExpr = new Expression(newTarget, expr.getMethodName(),
 149:                                             newArgs);
 150:         
 151:         // Fakes the result of Class.forName(<primitiveType>) to make it possible
 152:         // to hand such a type to the encoding process.
 153:         if (value instanceof Class && ((Class) value).isPrimitive())
 154:           newExpr.setValue(value);
 155:         
 156:         // Instantiates the new object.
 157:         try
 158:           {
 159:             newValue = newExpr.getValue();
 160: 
 161:             putCandidate(value, newValue);
 162:           }
 163:         catch (Exception e)
 164:           {
 165:             getExceptionListener().exceptionThrown(e);
 166:             
 167:             // In Statement.writeExpression we had no possibility to flags
 168:             // an erroneous state to the ScanEngine without behaving different
 169:             // to the JDK.            
 170:             scanEngine.revoke();
 171:           }
 172:         
 173:         writeObject(value);
 174: 
 175:       }
 176:     else if(value.getClass() == String.class || value.getClass() == Class.class)
 177:       {
 178:         writeObject(value);
 179:       }
 180: 
 181:     scanEngine.end();
 182:   }
 183: 
 184:   public void writeStatement(Statement stmt)
 185:   {
 186:     // In case of questions have a at the implementation note in
 187:     // writeExpression.
 188:     
 189:     scanEngine.writeStatement(stmt);
 190: 
 191:     //  Silently ignore out of bounds calls.
 192:     if (accessCounter <= 0)
 193:       return;
 194: 
 195:     Object target = stmt.getTarget();
 196: 
 197:     Object newTarget = get(target);
 198:     if (newTarget == null)
 199:       {
 200:         writeObject(target);
 201:         newTarget = get(target);
 202:       }
 203: 
 204:     Object[] args = stmt.getArguments();
 205:     Object[] newArgs = new Object[args.length];
 206: 
 207:     for (int i = 0; i < args.length; i++)
 208:       {
 209:         // Here is the difference to the original writeStatement
 210:         // method in Encoder. In case that the object is known or
 211:         // not an immutable we put it directly into the ScanEngine
 212:         // which will then generate an object reference for it.
 213:         newArgs[i] = get(args[i]);
 214:         if (newArgs[i] == null || isImmutableType(args[i].getClass()))
 215:           {
 216:             writeObject(args[i]);
 217:             newArgs[i] = get(args[i]);
 218:           }
 219:         else
 220:           scanEngine.writeObject(args[i]);
 221:       }
 222: 
 223:     Statement newStmt = new Statement(newTarget, stmt.getMethodName(), newArgs);
 224: 
 225:     try
 226:       {
 227:         newStmt.execute();
 228:       }
 229:     catch (Exception e)
 230:       {
 231:         getExceptionListener().exceptionThrown(e);
 232: 
 233:         // In Statement.writeStatement we had no possibility to flags
 234:         // an erroneous state to the ScanEngine without behaving different
 235:         // to the JDK.            
 236:         scanEngine.revoke();
 237:         return;
 238:       }
 239: 
 240:     scanEngine.end();
 241:   }
 242: 
 243:   public void writeObject(Object o)
 244:   {
 245:     accessCounter++;
 246:     
 247:     scanEngine.writeObject(o);
 248:     
 249:     if (get(o) == null);
 250:       super.writeObject(o);
 251:       
 252:     accessCounter--;
 253:   }
 254:   
 255:   public void setOwner(Object o)
 256:   {
 257:     owner = o;
 258:   }
 259: 
 260:   public Object getOwner()
 261:   {
 262:     return owner;
 263:   }
 264: 
 265: }