View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2006 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.services.xmlmerge.merge;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  
24  import org.jdom.DocType;
25  import org.jdom.Document;
26  import org.jdom.Element;
27  import org.jdom.JDOMException;
28  import org.jdom.input.DOMBuilder;
29  import org.jdom.input.SAXBuilder;
30  import org.jdom.output.DOMOutputter;
31  import org.jdom.output.Format;
32  import org.jdom.output.XMLOutputter;
33  import org.xml.sax.EntityResolver;
34  
35  import ch.elca.el4j.services.xmlmerge.AbstractXmlMergeException;
36  import ch.elca.el4j.services.xmlmerge.DocumentException;
37  import ch.elca.el4j.services.xmlmerge.Mapper;
38  import ch.elca.el4j.services.xmlmerge.Matcher;
39  import ch.elca.el4j.services.xmlmerge.MergeAction;
40  import ch.elca.el4j.services.xmlmerge.ParseException;
41  import ch.elca.el4j.services.xmlmerge.XmlMerge;
42  import ch.elca.el4j.services.xmlmerge.XmlMergeContext;
43  import ch.elca.el4j.services.xmlmerge.action.OrderedMergeAction;
44  import ch.elca.el4j.services.xmlmerge.factory.StaticOperationFactory;
45  import ch.elca.el4j.services.xmlmerge.mapper.IdentityMapper;
46  import ch.elca.el4j.services.xmlmerge.matcher.TagMatcher;
47  
48  // Checkstyle: MagicNumber off
49  
50  /**
51   * Default implementation of XmlMerge. Create all JDOM documents, then perform
52   * the merge into a new JDOM document.
53   *
54   * @svnLink $Revision: 3874 $;$Date: 2009-08-04 14:25:40 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/xml_merge/common/src/main/java/ch/elca/el4j/services/xmlmerge/merge/DefaultXmlMerge.java $
55   *
56   * @author Laurent Bovet (LBO)
57   * @author Alex Mathey (AMA)
58   */
59  public class DefaultXmlMerge implements XmlMerge {
60  
61  	/**
62  	 * Root merge action.
63  	 */
64  	private MergeAction m_rootMergeAction = new OrderedMergeAction();
65  
66  	/**
67  	 * Root matcher.
68  	 */
69  	private Matcher m_rootMatcher = new TagMatcher();
70  
71  	
72  	/**
73  	 * Creates a new DefaultXmlMerge instance.
74  	 */
75  	public DefaultXmlMerge() {
76  		m_rootMergeAction.setActionFactory(new StaticOperationFactory(
77  			new OrderedMergeAction()));
78  		m_rootMergeAction.setMapperFactory(new StaticOperationFactory(
79  			new IdentityMapper()));
80  		m_rootMergeAction.setMatcherFactory(new StaticOperationFactory(
81  			new TagMatcher()));
82  	}
83  
84  	/**
85  	 * {@inheritDoc}
86  	 */
87  	public void setRootMapper(Mapper rootMapper) { }
88  
89  	/**
90  	 * {@inheritDoc}
91  	 */
92  	public void setRootMergeAction(MergeAction rootMergeAction) {
93  		this.m_rootMergeAction = rootMergeAction;
94  	}
95  
96  	/**
97  	 * {@inheritDoc}
98  	 */
99  	public String merge(String[] sources) throws AbstractXmlMergeException {
100 
101 		InputStream[] inputStreams = new InputStream[sources.length];
102 
103 		for (int i = 0; i < sources.length; i++) {
104 			inputStreams[i] = new ByteArrayInputStream(sources[i].getBytes());
105 		}
106 
107 		InputStream merged = merge(inputStreams);
108 
109 		ByteArrayOutputStream result = new ByteArrayOutputStream();
110 
111 		try {
112 			byte[] buffer = new byte[1024];
113 			int len;
114 			while ((len = merged.read(buffer)) != -1) {
115 				result.write(buffer, 0, len);
116 			}
117 		} catch (IOException ioe) {
118 			// should never happen
119 			throw new RuntimeException(ioe);
120 		}
121 
122 		return result.toString();
123 	}
124 
125 	/**
126 	 * {@inheritDoc}
127 	 */
128 	public org.w3c.dom.Document merge(org.w3c.dom.Document[] sources)
129 		throws AbstractXmlMergeException {
130 		DOMBuilder domb = new DOMBuilder();
131 
132 		// to save all XML files as JDOM objects
133 		Document[] docs = new Document[sources.length];
134 
135 		for (int i = 0; i < sources.length; i++) {
136 			// ask JDOM to parse the given inputStream
137 			docs[i] = domb.build(sources[i]);
138 		}
139 
140 		Document result = doMerge(docs);
141 
142 		DOMOutputter outputter = new DOMOutputter();
143 
144 		try {
145 			return outputter.output(result);
146 		} catch (JDOMException e) {
147 			throw new DocumentException(result, e);
148 		}
149 	}
150 
151 	/**
152 	 * {@inheritDoc}
153 	 */
154 	public InputStream merge(InputStream[] sources)
155 		throws AbstractXmlMergeException {
156 		SAXBuilder sxb = new SAXBuilder();
157 
158 		EntityResolver entityResolver = XmlMergeContext.getEntityResolver();
159 		if (entityResolver != null) {
160 			sxb.setEntityResolver(entityResolver);
161 		}
162 		
163 		// to save all XML files as JDOM objects
164 		Document[] docs = new Document[sources.length];
165 
166 		for (int i = 0; i < sources.length; i++) {
167 			try {
168 				// ask JDOM to parse the given inputStream
169 				docs[i] = sxb.build(sources[i]);
170 			} catch (JDOMException e) {
171 				throw new ParseException(e);
172 			} catch (IOException ioe) {
173 				ioe.printStackTrace();
174 				throw new ParseException(ioe);
175 			}
176 		}
177 
178 		Document result = doMerge(docs);
179 
180 		Format prettyFormatter = Format.getPrettyFormat();
181 		// Use system line seperator to avoid problems
182 		// with carriage return under linux
183 		prettyFormatter.setLineSeparator(System.getProperty("line.separator"));
184 		XMLOutputter sortie = new XMLOutputter(prettyFormatter);
185 		
186 		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
187 
188 		try {
189 			sortie.output(result, buffer);
190 		} catch (IOException ex) {
191 			throw new DocumentException(result, ex);
192 		}
193 
194 		return new ByteArrayInputStream(buffer.toByteArray());
195 	}
196 
197 	/**
198 	 * Performs the actual merge.
199 	 *
200 	 * @param docs
201 	 *            The documents to merge
202 	 * @return The merged result document
203 	 * @throws AbstractXmlMergeException
204 	 *             If an error occurred during the merge
205 	 */
206 	private Document doMerge(Document[] docs) throws AbstractXmlMergeException {
207 		Document temporary = docs[0];
208 
209 		for (int i = 1; i < docs.length; i++) {
210 
211 			if (!m_rootMatcher.matches(temporary.getRootElement(), docs[i]
212 				.getRootElement())) {
213 				throw new IllegalArgumentException(
214 					"Root elements do not match.");
215 			}
216 
217 			Document output = new Document();
218 			if (docs[0].getDocType() != null) {
219 				output.setDocType((DocType) docs[0].getDocType().clone());
220 			}
221 			output.setRootElement(new Element("root"));
222 
223 			m_rootMergeAction.perform(temporary.getRootElement(), docs[i]
224 				.getRootElement(), output.getRootElement());
225 
226 			Element root = (Element) output.getRootElement().getChildren().get(
227 				0);
228 			root.detach();
229 
230 			temporary.setRootElement(root);
231 		}
232 
233 		return temporary;
234 	}
235 
236 }
237 
238 // Checkstyle: MagicNumber on