001/* ======================================================================== 002 * JCommon : a free general purpose class library for the Java(tm) platform 003 * ======================================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jcommon/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ------------------------- 028 * SplittingModelWriter.java 029 * ------------------------- 030 * (C)opyright 2003, by Thomas Morgner and Contributors. 031 * 032 * Original Author: Thomas Morgner; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * $Id: SplittingModelWriter.java,v 1.2 2005/10/18 13:32:20 mungady Exp $ 036 * 037 * Changes 038 * ------------------------- 039 * 12.11.2003 : Initial version 040 * 041 */ 042 043package org.jfree.xml.generator; 044 045import java.io.BufferedWriter; 046import java.io.File; 047import java.io.FileOutputStream; 048import java.io.IOException; 049import java.io.OutputStreamWriter; 050import java.util.ArrayList; 051import java.util.Arrays; 052import java.util.Iterator; 053 054import org.jfree.io.IOUtils; 055import org.jfree.util.HashNMap; 056import org.jfree.util.Log; 057import org.jfree.xml.generator.model.ClassDescription; 058import org.jfree.xml.generator.model.DescriptionModel; 059import org.jfree.xml.generator.model.ManualMappingInfo; 060import org.jfree.xml.generator.model.MappingModel; 061import org.jfree.xml.generator.model.MultiplexMappingInfo; 062import org.jfree.xml.util.ClassModelTags; 063 064/** 065 * A model writer that writes to multiple files. 066 */ 067public class SplittingModelWriter extends ModelWriter { 068 069 /** ??. */ 070 private HashNMap classDescriptionByPackage; 071 072 /** The sources. */ 073 private ArrayList sources; 074 075 /** The target file. */ 076 private File targetFile; 077 078 /** The file extension. */ 079 private String extension; 080 081 /** The plain file name. */ 082 private String plainFileName; 083 084 /** ??. */ 085 private HashNMap manualMappingByPackage; 086 087 /** ??. */ 088 private HashNMap multiplexMappingByPackage; 089 090 /** 091 * Creates a new instance. 092 */ 093 public SplittingModelWriter() { 094 super(); 095 } 096 097 /** 098 * Writes the model to the specified target. 099 * 100 * @param target the target file name. 101 * 102 * @throws IOException if there is an I/O problem. 103 */ 104 public synchronized void write(final String target) throws IOException { 105 106 final DescriptionModel model = getModel(); 107 this.sources = new ArrayList(Arrays.asList(model.getSources())); 108 this.targetFile = new File(target); 109 this.plainFileName = IOUtils.getInstance().stripFileExtension(this.targetFile.getName()); 110 this.extension = IOUtils.getInstance().getFileExtension(target); 111 112 // split into classDescriptionByPackage ... 113 this.classDescriptionByPackage = new HashNMap(); 114 for (int i = 0; i < model.size(); i++) { 115 final ClassDescription cd = model.get(i); 116 if (cd.getSource() == null) { 117 final String packageName = getPackage(cd.getObjectClass()); 118 final String includeFileName = this.plainFileName + "-" + packageName 119 + this.extension; 120 this.classDescriptionByPackage.add(includeFileName, cd); 121 } 122 else { 123 this.classDescriptionByPackage.add(cd.getSource(), cd); 124 } 125 } 126 127 final MappingModel mappingModel = model.getMappingModel(); 128 129 // split manual mappings into packages ... 130 final ManualMappingInfo[] manualMappings = mappingModel.getManualMapping(); 131 this.manualMappingByPackage = new HashNMap(); 132 for (int i = 0; i < manualMappings.length; i++) { 133 final ManualMappingInfo mapping = manualMappings[i]; 134 if (mapping.getSource() == null) { 135 this.manualMappingByPackage.add("", mapping); 136 } 137 else { 138 this.manualMappingByPackage.add(mapping.getSource(), mapping); 139 } 140 } 141 142 // split manual mappings into packages ... 143 final MultiplexMappingInfo[] multiplexMappings = mappingModel.getMultiplexMapping(); 144 this.multiplexMappingByPackage = new HashNMap(); 145 for (int i = 0; i < multiplexMappings.length; i++) { 146 final MultiplexMappingInfo mapping = multiplexMappings[i]; 147 if (mapping.getSource() == null) { 148 this.multiplexMappingByPackage.add("", mapping); 149 } 150 else { 151 this.multiplexMappingByPackage.add(mapping.getSource(), mapping); 152 } 153 } 154 155 156 final Object[] keys = this.classDescriptionByPackage.keySet().toArray(); 157 for (int i = 0; i < keys.length; i++) { 158 159 final String includeFileName = (String) keys[i]; 160 // write if not contained in the master file ... 161 if (!includeFileName.equals("")) { 162 writePackageFile(includeFileName); 163 } 164 } 165 166 writeMasterFile(); 167 168 this.manualMappingByPackage = null; 169 this.multiplexMappingByPackage = null; 170 this.classDescriptionByPackage = null; 171 this.sources = null; 172 } 173 174 /** 175 * Writes a file for a package. 176 * 177 * @param includeFileName the name of the file. 178 * 179 * @throws IOException if there is an I/O problem. 180 */ 181 private void writePackageFile(final String includeFileName) throws IOException { 182 183 final Iterator values = this.classDescriptionByPackage.getAll(includeFileName); 184 final Iterator manualMappings = this.manualMappingByPackage.getAll(includeFileName); 185 final Iterator multiplexMappings = this.multiplexMappingByPackage.getAll(includeFileName); 186 if (!values.hasNext() && !manualMappings.hasNext() && !multiplexMappings.hasNext()) { 187 return; 188 } 189 190 Log.debug ("Writing included file: " + includeFileName); 191 // the current file need no longer be included manually ... 192 this.sources.remove(includeFileName); 193 194 final BufferedWriter writer = new BufferedWriter( 195 new OutputStreamWriter( 196 new FileOutputStream( 197 new File(this.targetFile.getParentFile(), includeFileName) 198 ), 199 "UTF-8" 200 ) 201 ); 202 203 writeXMLHeader(writer); 204 writeStandardComment(writer, getModel().getModelComments()); 205 getWriterSupport().writeTag(writer, ClassModelTags.OBJECTS_TAG); 206 207 while (values.hasNext()) { 208 final ClassDescription cd = (ClassDescription) values.next(); 209 writeClassDescription(writer, cd); 210 } 211 212 213 while (manualMappings.hasNext()) { 214 final ManualMappingInfo mi = (ManualMappingInfo) manualMappings.next(); 215 writeManualMapping(writer, mi); 216 } 217 218 while (multiplexMappings.hasNext()) { 219 final MultiplexMappingInfo mi = (MultiplexMappingInfo) multiplexMappings.next(); 220 writeMultiplexMapping(writer, mi); 221 } 222 223 writeCloseComment(writer, getModel().getModelComments()); 224 getWriterSupport().writeCloseTag(writer, ClassModelTags.OBJECTS_TAG); 225 writer.close(); 226 } 227 228 /** 229 * Returns the name of the package for the given class. This is a 230 * workaround for the classloader behaviour of JDK1.2.2 where no 231 * package objects are created. 232 * 233 * @param c the class for which we search the package. 234 * 235 * @return the name of the package, never null. 236 */ 237 public static String getPackage(final Class c) { 238 final String className = c.getName(); 239 final int idx = className.lastIndexOf('.'); 240 if (idx <= 0) { 241 // the default package 242 return ""; 243 } 244 else { 245 return className.substring(0, idx); 246 } 247 } 248 249 /** 250 * Writes the master file. 251 * 252 * @throws IOException if there is an I/O problem. 253 */ 254 private void writeMasterFile() throws IOException { 255 256 Log.debug ("Writing master file: " + this.targetFile); 257 258 final BufferedWriter writer = new BufferedWriter( 259 new OutputStreamWriter(new FileOutputStream(this.targetFile), "UTF-8") 260 ); 261 262 writeXMLHeader(writer); 263 writeStandardComment(writer, getModel().getModelComments()); 264 getWriterSupport().writeTag(writer, ClassModelTags.OBJECTS_TAG); 265 266 for (int i = 0; i < this.sources.size(); i++) { 267 final String includeFileName = (String) this.sources.get(i); 268 if (!includeFileName.equals("")) { 269 writeTag(writer, ClassModelTags.INCLUDE_TAG, ClassModelTags.SOURCE_ATTR, 270 includeFileName, getModel().getIncludeComment(includeFileName)); 271 } 272 } 273 274 final Object[] keys = this.classDescriptionByPackage.keySet().toArray(); 275 Arrays.sort(keys); 276 for (int i = 0; i < keys.length; i++) { 277 final String includeFileName = (String) keys[i]; 278 if (!includeFileName.equals("")) { 279 writeTag(writer, ClassModelTags.INCLUDE_TAG, ClassModelTags.SOURCE_ATTR, 280 includeFileName, getModel().getIncludeComment(includeFileName)); 281 } 282 } 283 284 final Iterator values = this.classDescriptionByPackage.getAll(""); 285 while (values.hasNext()) { 286 final ClassDescription cd = (ClassDescription) values.next(); 287 writeClassDescription(writer, cd); 288 } 289 290 final Iterator manualMappings = this.manualMappingByPackage.getAll(""); 291 while (manualMappings.hasNext()) { 292 final ManualMappingInfo mi = (ManualMappingInfo) manualMappings.next(); 293 writeManualMapping(writer, mi); 294 } 295 296 final Iterator multiplexMappings = this.multiplexMappingByPackage.getAll(""); 297 while (multiplexMappings.hasNext()) { 298 final MultiplexMappingInfo mi = (MultiplexMappingInfo) multiplexMappings.next(); 299 writeMultiplexMapping(writer, mi); 300 } 301 302 writeCloseComment(writer, getModel().getModelComments()); 303 getWriterSupport().writeCloseTag(writer, ClassModelTags.OBJECTS_TAG); 304 writer.close(); 305 } 306 307}