001/*
002 * VisitorStrategy.java January 2010
003 *
004 * Copyright (C) 2010, Niall Gallagher <niallg@users.sf.net>
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
015 * implied. See the License for the specific language governing 
016 * permissions and limitations under the License.
017 */
018
019package org.simpleframework.xml.strategy;
020
021import java.util.Map;
022
023import org.simpleframework.xml.stream.InputNode;
024import org.simpleframework.xml.stream.NodeMap;
025import org.simpleframework.xml.stream.OutputNode;
026
027/**
028 * The <code>VisitorStrategy</code> object is a simplification of a
029 * strategy, which allows manipulation of the serialization process.
030 * Typically implementing a <code>Strategy</code> is impractical as
031 * it requires the implementation to determine the type a node
032 * represents. Instead it is often easier to visit each node that
033 * is being serialized or deserialized and manipulate it so that 
034 * the resulting XML can be customized. 
035 * <p>
036 * To perform customization in this way a <code>Visitor</code> can
037 * be implemented. This can be passed to this strategy which will 
038 * ensure the visitor is given each XML element as it is either 
039 * being serialized or deserialized. Such an inversion of control
040 * allows the nodes to be manipulated with little effort. By 
041 * default this used <code>TreeStrategy</code> object as a default
042 * strategy to delegate to. However, any strategy can be used.
043 * 
044 * @author Niall Gallagher
045 * 
046 * @see org.simpleframework.xml.strategy.Visitor
047 */
048public class VisitorStrategy implements Strategy {
049   
050   /**
051    * This is the strategy that is delegated to by this strategy.
052    */
053   private final Strategy strategy;
054   
055   /**
056    * This is the visitor that is used to intercept serialization.
057    */
058   private final Visitor visitor;
059   
060   /**
061    * Constructor for the <code>VisitorStrategy</code> object. This
062    * strategy requires a visitor implementation that can be used
063    * to intercept the serialization and deserialization process.
064    * 
065    * @param visitor this is the visitor used for interception
066    */
067   public VisitorStrategy(Visitor visitor) {
068      this(visitor, new TreeStrategy());
069   }
070   
071   /**
072    * Constructor for the <code>VisitorStrategy</code> object. This
073    * strategy requires a visitor implementation that can be used
074    * to intercept the serialization and deserialization process.
075    * 
076    * @param visitor this is the visitor used for interception
077    * @param strategy this is the strategy to be delegated to
078    */
079   public VisitorStrategy(Visitor visitor, Strategy strategy) {
080      this.strategy = strategy;
081      this.visitor = visitor;
082   }
083
084   /**
085    * This method will read with  an internal strategy after it has
086    * been intercepted by the visitor. Interception of the XML node
087    * before it is delegated to the internal strategy allows the 
088    * visitor to change some attributes or details before the node
089    * is interpreted by the strategy.
090    * 
091    * @param type this is the type of the root element expected
092    * @param node this is the node map used to resolve an override
093    * @param map this is used to maintain contextual information
094    * 
095    * @return the value that should be used to describe the instance
096    */
097   public Value read(Type type, NodeMap<InputNode> node, Map map) throws Exception {
098      if(visitor != null) {
099         visitor.read(type, node);
100      }
101      return strategy.read(type, node, map);
102   }
103
104   /**
105    * This method will write with an internal strategy before it has
106    * been intercepted by the visitor. Interception of the XML node
107    * before it is delegated to the internal strategy allows the 
108    * visitor to change some attributes or details before the node
109    * is interpreted by the strategy.
110    * 
111    * @param type this is the type of the root element expected
112    * @param node this is the node map used to resolve an override
113    * @param map this is used to maintain contextual information
114    * 
115    * @return the value that should be used to describe the instance
116    */
117   public boolean write(Type type, Object value, NodeMap<OutputNode> node, Map map) throws Exception {
118      boolean result = strategy.write(type, value, node, map); 
119      
120      if(visitor != null) {
121         visitor.write(type, node);
122      }
123      return result;
124   }
125}