PageRenderTime 36ms CodeModel.GetById 12ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 25package org.hudsonci.utils.marshal.xref;
 26
 27import org.hudsonci.utils.marshal.xref.XReference.InstanceHolder;
 28import com.thoughtworks.xstream.converters.ConversionException;
 29import com.thoughtworks.xstream.converters.MarshallingContext;
 30import com.thoughtworks.xstream.converters.UnmarshallingContext;
 31import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter;
 32import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
 33import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 34import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
 35import com.thoughtworks.xstream.mapper.Mapper;
 36
 37import java.io.IOException;
 38import java.lang.ref.SoftReference;
 39
 40import static com.google.common.base.Preconditions.checkNotNull;
 41
 42/**
 43 * Converter for {@link XReference} types.
 44 *
 45 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
 46 * @since 2.1.0
 47 */
 48public abstract class XReferenceConverter
 49    extends AbstractReflectionConverter
 50{
 51    protected HolderType holderType = HolderType.HARD;
 52
 53    public XReferenceConverter(final Mapper mapper, final ReflectionProvider reflection) {
 54        super(mapper, reflection);
 55    }
 56
 57    public HolderType getHolderType() {
 58        return holderType;
 59    }
 60
 61    public void setHolderType(final HolderType type) {
 62        this.holderType = checkNotNull(type);
 63    }
 64
 65    public boolean canConvert(final Class type) {
 66        return XReference.class.isAssignableFrom(type);
 67    }
 68
 69    @Override
 70    protected void doMarshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
 71        // Do the default marshalling for the reference container
 72        super.doMarshal(source, writer, context);
 73
 74        // Then delegate the storage of the reference target
 75        XReference ref = (XReference)source;
 76        Object target = ref.get();
 77        if (target != null) {
 78            try {
 79                store(ref);
 80                ref.holder = createStoredHolder(ref, target);
 81            }
 82            catch (Exception e) {
 83                throw new ConversionException("Failed to marshal reference: " + ref, e);
 84            }
 85        }
 86    }
 87
 88    @Override
 89    public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader, final UnmarshallingContext context) {
 90        // Do the default unmarshalling for the reference container
 91        XReference ref = (XReference) super.doUnmarshal(result, reader, context);
 92        ref.holder = createUnmarshalHolder(ref);
 93        return ref;
 94    }
 95
 96    /**
 97     * Provides reference storing behavior.
 98     */
 99    protected abstract void store(final XReference ref) throws IOException;
100
101    /**
102     * Provides reference loading behavior.
103     */
104    protected abstract Object load(final XReference ref) throws IOException;
105
106    /**
107     * Create the holder to be used after the reference has been stored.
108     */
109    @SuppressWarnings({"unchecked"})
110    protected XReference.Holder createStoredHolder(final XReference ref, final Object target) {
111        switch (holderType) {
112            case HARD:
113                return new InstanceHolder(target);
114            case SOFT:
115                return new SoftUnmarshalHolder(ref, target);
116            default:
117                throw new Error();
118        }
119    }
120
121    /**
122     * Create the holder to be used after the reference has been unmarshalled.
123     */
124    protected XReference.Holder createUnmarshalHolder(final XReference ref) {
125        switch (holderType) {
126            case HARD:
127                return new UnmarshalHolder(ref);
128            case SOFT:
129                return new SoftUnmarshalHolder(ref);
130            default:
131                throw new Error();
132        }
133    }
134
135    /**
136     * Support for {@link XReference.Holder} implementations.
137     */
138    protected abstract class HolderSupport
139        implements XReference.Holder
140    {
141        protected final XReference ref;
142
143        protected HolderSupport(final XReference ref) {
144            this.ref = checkNotNull(ref);
145        }
146
147        protected Object doLoad() {
148            try {
149                return load(ref);
150            }
151            catch (Exception e) {
152                throw new ConversionException("Failed to unmarshal reference: " + ref, e);
153            }
154        }
155    }
156
157    /**
158     * Default holder types.
159     */
160    public static enum HolderType
161    {
162        /**
163         * Use hard references.
164         */
165        HARD,
166
167        /**
168         * Use soft references.
169         */
170        SOFT
171    }
172
173    /**
174     * Unmarshalling holder with a hard reference.
175     */
176    protected class UnmarshalHolder
177        extends HolderSupport
178    {
179        protected Object instance;
180
181        protected UnmarshalHolder(final XReference ref) {
182            super(ref);
183        }
184
185        public Object get() {
186            if (instance == null) {
187                instance = doLoad();
188            }
189            return instance;
190        }
191
192        @Override
193        public String toString() {
194            return "UnmarshalHolder{" +
195                "instance=" + instance +
196                '}';
197        }
198    }
199
200    /**
201     * Unmarshalling holder with a soft reference.
202     */
203    @SuppressWarnings({"unchecked"})
204    protected class SoftUnmarshalHolder
205        extends HolderSupport
206    {
207        protected SoftReference instance;
208
209        protected SoftUnmarshalHolder(final XReference ref) {
210            super(ref);
211        }
212
213        protected SoftUnmarshalHolder(final XReference ref, final Object target) {
214            super(ref);
215            checkNotNull(target);
216            this.instance = new SoftReference(target);
217        }
218
219        public Object get() {
220            Object target;
221            if (instance == null || (target = instance.get()) == null) {
222                target = doLoad();
223                instance = new SoftReference(target);
224            }
225            return target;
226        }
227
228        @Override
229        public String toString() {
230            return "SoftUnmarshalHolder{" +
231                "instance=" + instance +
232                '}';
233        }
234    }
235}