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