1. /*
  2. * @(#)Encoder.java 1.16 03/01/27
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.beans;
  8. import java.io.*;
  9. import java.util.*;
  10. /**
  11. * An <code>Encoder</code> is a class which can be used to create
  12. * files or streams that encode the state of a collection of
  13. * JavaBeans in terms of their public APIs. The <code>Encoder</code>,
  14. * in conjunction with its persistence delegates, is responsible for
  15. * breaking the object graph down into a series of <code>Statements</code>s
  16. * and <code>Expression</code>s which can be used to create it.
  17. * A subclass typically provides a syntax for these expressions
  18. * using some human readable form - like Java source code or XML.
  19. *
  20. * @since 1.4
  21. *
  22. * @version 1.3 11/15/00
  23. * @author Philip Milne
  24. */
  25. public class Encoder {
  26. private HashMap bindings = new IdentityHashtable();
  27. private ExceptionListener exceptionListener;
  28. boolean executeStatements = true;
  29. private HashMap attributes;
  30. /**
  31. * Write the specified object to the output stream.
  32. * The serialized form will denote a series of
  33. * expressions, the combined effect of which will create
  34. * an equivalent object when the input stream is read.
  35. * By default, the object is assumed to be a <em>JavaBean</em>
  36. * with a nullary constructor, whose state is defined by
  37. * the matching pairs of "setter" and "getter" methods
  38. * returned by the Introspector.
  39. *
  40. * @param o The object to be written to the stream.
  41. *
  42. * @see XMLDecoder#readObject
  43. */
  44. protected void writeObject(Object o) {
  45. // System.out.println("Encoder::writeObject: " + NameGenerator.instanceName(o));
  46. if (o == this) {
  47. return;
  48. }
  49. PersistenceDelegate info = getPersistenceDelegate(o == null ? null : o.getClass());
  50. info.writeObject(o, this);
  51. }
  52. /**
  53. * Sets the exception handler for this stream to <code>exceptionListener</code>.
  54. * The exception handler is notified when this stream catches recoverable
  55. * exceptions.
  56. *
  57. * @param exceptionListener The exception handler for this stream.
  58. *
  59. * @see #getExceptionListener
  60. */
  61. public void setExceptionListener(ExceptionListener exceptionListener) {
  62. this.exceptionListener = exceptionListener;
  63. }
  64. /**
  65. * Gets the exception handler for this stream.
  66. *
  67. * @return The exception handler for this stream.
  68. *
  69. * @see #setExceptionListener
  70. */
  71. public ExceptionListener getExceptionListener() {
  72. return (exceptionListener != null) ? exceptionListener : Statement.defaultExceptionListener;
  73. }
  74. Object getValue(Expression exp) {
  75. try {
  76. return (exp == null) ? null : exp.getValue();
  77. }
  78. catch (Exception e) {
  79. getExceptionListener().exceptionThrown(e);
  80. throw new RuntimeException("failed to evaluate: " + exp.toString());
  81. }
  82. }
  83. void execute(Statement smt) {
  84. try {
  85. smt.execute();
  86. }
  87. catch (Exception e) {
  88. getExceptionListener().exceptionThrown(e);
  89. getExceptionListener().exceptionThrown(new Exception("discarding statement " + smt));
  90. }
  91. }
  92. /**
  93. * Returns the persistence delegate for the given type.
  94. * The persistence delegate is calculated
  95. * by applying the following of rules in order:
  96. * <ul>
  97. * <li>
  98. * If the type is an array, an internal persistence
  99. * delegate is returned which will instantiate an
  100. * array of the appropriate type and length, initializing
  101. * each of its elements as if they are properties.
  102. * <li>
  103. * If the type is a proxy, an internal persistence
  104. * delegate is returned which will instantiate a
  105. * new proxy instance using the static
  106. * "newProxyInstance" method defined in the
  107. * Proxy class.
  108. * <li>
  109. * If the BeanInfo for this type has a <code>BeanDescriptor</code>
  110. * which defined a "persistenceDelegate" property, this
  111. * value is returned.
  112. * <li>
  113. * In all other cases the default persistence delegate
  114. * is returned. The default persistence delegate assumes
  115. * the type is a <em>JavaBean</em>, implying that it has a nullary constructor
  116. * and that its state may be characterized by the matching pairs
  117. * of "setter" and "getter" methods returned by the Introspector.
  118. * </ul>
  119. *
  120. * @param type The type of the object.
  121. * @return The persistence delegate for this type of object.
  122. *
  123. * @see #setPersistenceDelegate
  124. * @see java.beans.Introspector#getBeanInfo
  125. * @see java.beans.BeanInfo#getBeanDescriptor
  126. */
  127. public PersistenceDelegate getPersistenceDelegate(Class type) {
  128. return MetaData.getPersistenceDelegate(type);
  129. }
  130. /**
  131. * Sets the persistence delegate associated with this <code>type</code> to
  132. * <code>persistenceDelegate</code>.
  133. *
  134. * @param type The class of objects that <code>persistenceDelegate</code> applies to.
  135. * @param persistenceDelegate The persistence delegate for instances of <code>type</code>.
  136. *
  137. * @see #getPersistenceDelegate
  138. * @see java.beans.Introspector#getBeanInfo
  139. * @see java.beans.BeanInfo#getBeanDescriptor
  140. */
  141. public void setPersistenceDelegate(Class type, PersistenceDelegate persistenceDelegate) {
  142. MetaData.setPersistenceDelegate(type, persistenceDelegate);
  143. }
  144. /**
  145. * Removes the entry for this instance, returning the old entry.
  146. *
  147. * @param oldInstance The entry that should be removed.
  148. * @return The entry that was removed.
  149. *
  150. * @see #get
  151. */
  152. public Object remove(Object oldInstance) {
  153. Expression exp = (Expression)bindings.remove(oldInstance);
  154. return getValue(exp);
  155. }
  156. /**
  157. * Returns a tentative value for <code>oldInstance</code> in
  158. * the environment created by this stream. A persistence
  159. * delegate can use its <code>mutatesTo</code> method to
  160. * determine whether this value may be initialized to
  161. * form the equivalent object at the output or whether
  162. * a new object must be instantiated afresh. If the
  163. * stream has not yet seen this value, null is returned.
  164. *
  165. * @param oldInstance The instance to be looked up.
  166. * @return The object, null if the object has not been seen before.
  167. */
  168. public Object get(Object oldInstance) {
  169. if (oldInstance == null || oldInstance == this || oldInstance.getClass() == String.class) {
  170. return oldInstance;
  171. }
  172. Expression exp = (Expression)bindings.get(oldInstance);
  173. return getValue(exp);
  174. }
  175. private Object writeObject1(Object oldInstance) {
  176. Object o = get(oldInstance);
  177. if (o == null) {
  178. writeObject(oldInstance);
  179. o = get(oldInstance);
  180. }
  181. return o;
  182. }
  183. private Statement cloneStatement(Statement oldExp) {
  184. Object oldTarget = oldExp.getTarget();
  185. Object newTarget = writeObject1(oldTarget);
  186. Object[] oldArgs = oldExp.getArguments();
  187. Object[] newArgs = new Object[oldArgs.length];
  188. for (int i = 0; i < oldArgs.length; i++) {
  189. newArgs[i] = writeObject1(oldArgs[i]);
  190. }
  191. if (oldExp.getClass() == Statement.class) {
  192. return new Statement(newTarget, oldExp.getMethodName(), newArgs);
  193. }
  194. else {
  195. return new Expression(newTarget, oldExp.getMethodName(), newArgs);
  196. }
  197. }
  198. /**
  199. * Writes statement <code>oldStm</code> to the stream.
  200. * The <code>oldStm</code> should be written entirely
  201. * in terms of the callers environment, i.e. the
  202. * target and all arguments should be part of the
  203. * object graph being written. These expressions
  204. * represent a series of "what happened" expressions
  205. * which tell the output stream how to produce an
  206. * object graph like the original.
  207. * <p>
  208. * The implementation of this method will produce
  209. * a second expression to represent the same expression in
  210. * an environment that will exist when the stream is read.
  211. * This is achieved simply by calling <code>writeObject</code>
  212. * on the target and all the arguments and building a new
  213. * expression with the results.
  214. *
  215. * @param oldStm The expression to be written to the stream.
  216. */
  217. public void writeStatement(Statement oldStm) {
  218. // System.out.println("writeStatement: " + oldExp);
  219. Statement newStm = cloneStatement(oldStm);
  220. if (oldStm.getTarget() != this && executeStatements) {
  221. execute(newStm);
  222. }
  223. }
  224. /**
  225. * The implementation first checks to see if an
  226. * expression with this value has already been written.
  227. * If not, the expression is cloned, using
  228. * the same procedure as <code>writeStatement</code>,
  229. * and the value of this expression is reconciled
  230. * with the value of the cloned expression
  231. * by calling <code>writeObject</code>.
  232. *
  233. * @param oldExp The expression to be written to the stream.
  234. */
  235. public void writeExpression(Expression oldExp) {
  236. // System.out.println("Encoder::writeExpression: " + oldExp);
  237. Object oldValue = getValue(oldExp);
  238. if (get(oldValue) != null) {
  239. return;
  240. }
  241. bindings.put(oldValue, (Expression)cloneStatement(oldExp));
  242. writeObject(oldValue);
  243. }
  244. void clear() {
  245. bindings.clear();
  246. }
  247. // Package private method for setting an attributes table for the encoder
  248. void setAttribute(Object key, Object value) {
  249. if (attributes == null) {
  250. attributes = new HashMap();
  251. }
  252. attributes.put(key, value);
  253. }
  254. Object getAttribute(Object key) {
  255. if (attributes == null) {
  256. return null;
  257. }
  258. return attributes.get(key);
  259. }
  260. }