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:             return;
 173:           }
 174:         
 175:         writeObject(value);
 176: 
 177:       }
 178:     else if(value.getClass() == String.class || value.getClass() == Class.class)
 179:       {
 180:         writeObject(value);
 181:       }
 182: 
 183:     scanEngine.end();
 184:   }
 185: 
 186:   public void writeStatement(Statement stmt)
 187:   {
 188:     // In case of questions have a at the implementation note in
 189:     // writeExpression.
 190:     
 191:     scanEngine.writeStatement(stmt);
 192: 
 193:     //  Silently ignore out of bounds calls.
 194:     if (accessCounter <= 0)
 195:       return;
 196: 
 197:     Object target = stmt.getTarget();
 198: 
 199:     Object newTarget = get(target);
 200:     if (newTarget == null)
 201:       {
 202:         writeObject(target);
 203:         newTarget = get(target);
 204:       }
 205: 
 206:     Object[] args = stmt.getArguments();
 207:     Object[] newArgs = new Object[args.length];
 208: 
 209:     for (int i = 0; i < args.length; i++)
 210:       {
 211:         // Here is the difference to the original writeStatement
 212:         // method in Encoder. In case that the object is known or
 213:         // not an immutable we put it directly into the ScanEngine
 214:         // which will then generate an object reference for it.
 215:         newArgs[i] = get(args[i]);
 216:         if (newArgs[i] == null || isImmutableType(args[i].getClass()))
 217:           {
 218:             writeObject(args[i]);
 219:             newArgs[i] = get(args[i]);
 220:           }
 221:         else
 222:           scanEngine.writeObject(args[i]);
 223:       }
 224: 
 225:     Statement newStmt = new Statement(newTarget, stmt.getMethodName(), newArgs);
 226: 
 227:     try
 228:       {
 229:         newStmt.execute();
 230:       }
 231:     catch (Exception e)
 232:       {
 233:         getExceptionListener().exceptionThrown(e);
 234: 
 235:         // In Statement.writeStatement we had no possibility to flags
 236:         // an erroneous state to the ScanEngine without behaving different
 237:         // to the JDK.            
 238:         scanEngine.revoke();
 239:         return;
 240:       }
 241: 
 242:     scanEngine.end();
 243:   }
 244: 
 245:   public void writeObject(Object o)
 246:   {
 247:     accessCounter++;
 248:     
 249:     scanEngine.writeObject(o);
 250:     
 251:     if (get(o) == null)
 252:       super.writeObject(o);
 253:       
 254:     accessCounter--;
 255:   }
 256:   
 257:   public void setOwner(Object o)
 258:   {
 259:     owner = o;
 260:   }
 261: 
 262:   public Object getOwner()
 263:   {
 264:     return owner;
 265:   }
 266: 
 267: }