/hudson-utils/src/main/java/org/hudsonci/utils/marshal/xref/XReferenceConverter.java

http://github.com/hudson/hudson · Java · 235 lines · 143 code · 30 blank · 62 comment · 10 complexity · 7678b106a9c4615379a236ae9dc1c68c MD5 · raw file

  1. /**
  2. * The MIT License
  3. *
  4. * Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. package org.hudsonci.utils.marshal.xref;
  25. import org.hudsonci.utils.marshal.xref.XReference.InstanceHolder;
  26. import com.thoughtworks.xstream.converters.ConversionException;
  27. import com.thoughtworks.xstream.converters.MarshallingContext;
  28. import com.thoughtworks.xstream.converters.UnmarshallingContext;
  29. import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter;
  30. import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
  31. import com.thoughtworks.xstream.io.HierarchicalStreamReader;
  32. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  33. import com.thoughtworks.xstream.mapper.Mapper;
  34. import java.io.IOException;
  35. import java.lang.ref.SoftReference;
  36. import static com.google.common.base.Preconditions.checkNotNull;
  37. /**
  38. * Converter for {@link XReference} types.
  39. *
  40. * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
  41. * @since 2.1.0
  42. */
  43. public abstract class XReferenceConverter
  44. extends AbstractReflectionConverter
  45. {
  46. protected HolderType holderType = HolderType.HARD;
  47. public XReferenceConverter(final Mapper mapper, final ReflectionProvider reflection) {
  48. super(mapper, reflection);
  49. }
  50. public HolderType getHolderType() {
  51. return holderType;
  52. }
  53. public void setHolderType(final HolderType type) {
  54. this.holderType = checkNotNull(type);
  55. }
  56. public boolean canConvert(final Class type) {
  57. return XReference.class.isAssignableFrom(type);
  58. }
  59. @Override
  60. protected void doMarshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
  61. // Do the default marshalling for the reference container
  62. super.doMarshal(source, writer, context);
  63. // Then delegate the storage of the reference target
  64. XReference ref = (XReference)source;
  65. Object target = ref.get();
  66. if (target != null) {
  67. try {
  68. store(ref);
  69. ref.holder = createStoredHolder(ref, target);
  70. }
  71. catch (Exception e) {
  72. throw new ConversionException("Failed to marshal reference: " + ref, e);
  73. }
  74. }
  75. }
  76. @Override
  77. public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader, final UnmarshallingContext context) {
  78. // Do the default unmarshalling for the reference container
  79. XReference ref = (XReference) super.doUnmarshal(result, reader, context);
  80. ref.holder = createUnmarshalHolder(ref);
  81. return ref;
  82. }
  83. /**
  84. * Provides reference storing behavior.
  85. */
  86. protected abstract void store(final XReference ref) throws IOException;
  87. /**
  88. * Provides reference loading behavior.
  89. */
  90. protected abstract Object load(final XReference ref) throws IOException;
  91. /**
  92. * Create the holder to be used after the reference has been stored.
  93. */
  94. @SuppressWarnings({"unchecked"})
  95. protected XReference.Holder createStoredHolder(final XReference ref, final Object target) {
  96. switch (holderType) {
  97. case HARD:
  98. return new InstanceHolder(target);
  99. case SOFT:
  100. return new SoftUnmarshalHolder(ref, target);
  101. default:
  102. throw new Error();
  103. }
  104. }
  105. /**
  106. * Create the holder to be used after the reference has been unmarshalled.
  107. */
  108. protected XReference.Holder createUnmarshalHolder(final XReference ref) {
  109. switch (holderType) {
  110. case HARD:
  111. return new UnmarshalHolder(ref);
  112. case SOFT:
  113. return new SoftUnmarshalHolder(ref);
  114. default:
  115. throw new Error();
  116. }
  117. }
  118. /**
  119. * Support for {@link XReference.Holder} implementations.
  120. */
  121. protected abstract class HolderSupport
  122. implements XReference.Holder
  123. {
  124. protected final XReference ref;
  125. protected HolderSupport(final XReference ref) {
  126. this.ref = checkNotNull(ref);
  127. }
  128. protected Object doLoad() {
  129. try {
  130. return load(ref);
  131. }
  132. catch (Exception e) {
  133. throw new ConversionException("Failed to unmarshal reference: " + ref, e);
  134. }
  135. }
  136. }
  137. /**
  138. * Default holder types.
  139. */
  140. public static enum HolderType
  141. {
  142. /**
  143. * Use hard references.
  144. */
  145. HARD,
  146. /**
  147. * Use soft references.
  148. */
  149. SOFT
  150. }
  151. /**
  152. * Unmarshalling holder with a hard reference.
  153. */
  154. protected class UnmarshalHolder
  155. extends HolderSupport
  156. {
  157. protected Object instance;
  158. protected UnmarshalHolder(final XReference ref) {
  159. super(ref);
  160. }
  161. public Object get() {
  162. if (instance == null) {
  163. instance = doLoad();
  164. }
  165. return instance;
  166. }
  167. @Override
  168. public String toString() {
  169. return "UnmarshalHolder{" +
  170. "instance=" + instance +
  171. '}';
  172. }
  173. }
  174. /**
  175. * Unmarshalling holder with a soft reference.
  176. */
  177. @SuppressWarnings({"unchecked"})
  178. protected class SoftUnmarshalHolder
  179. extends HolderSupport
  180. {
  181. protected SoftReference instance;
  182. protected SoftUnmarshalHolder(final XReference ref) {
  183. super(ref);
  184. }
  185. protected SoftUnmarshalHolder(final XReference ref, final Object target) {
  186. super(ref);
  187. checkNotNull(target);
  188. this.instance = new SoftReference(target);
  189. }
  190. public Object get() {
  191. Object target;
  192. if (instance == null || (target = instance.get()) == null) {
  193. target = doLoad();
  194. instance = new SoftReference(target);
  195. }
  196. return target;
  197. }
  198. @Override
  199. public String toString() {
  200. return "SoftUnmarshalHolder{" +
  201. "instance=" + instance +
  202. '}';
  203. }
  204. }
  205. }