Source for org.jfree.xml.generator.SplittingModelWriter

   1: /* ========================================================================
   2:  * JCommon : a free general purpose class library for the Java(tm) platform
   3:  * ========================================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  * 
   7:  * Project Info:  http://www.jfree.org/jcommon/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  * 
  27:  * -------------------------
  28:  * SplittingModelWriter.java
  29:  * -------------------------
  30:  * (C)opyright 2003, by Thomas Morgner and Contributors.
  31:  *
  32:  * Original Author:  Thomas Morgner;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * $Id: SplittingModelWriter.java,v 1.2 2005/10/18 13:32:20 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------------------------
  39:  * 12.11.2003 : Initial version
  40:  *
  41:  */
  42: 
  43: package org.jfree.xml.generator;
  44: 
  45: import java.io.BufferedWriter;
  46: import java.io.File;
  47: import java.io.FileOutputStream;
  48: import java.io.IOException;
  49: import java.io.OutputStreamWriter;
  50: import java.util.ArrayList;
  51: import java.util.Arrays;
  52: import java.util.Iterator;
  53: 
  54: import org.jfree.io.IOUtils;
  55: import org.jfree.util.HashNMap;
  56: import org.jfree.util.Log;
  57: import org.jfree.xml.generator.model.ClassDescription;
  58: import org.jfree.xml.generator.model.DescriptionModel;
  59: import org.jfree.xml.generator.model.ManualMappingInfo;
  60: import org.jfree.xml.generator.model.MappingModel;
  61: import org.jfree.xml.generator.model.MultiplexMappingInfo;
  62: import org.jfree.xml.util.ClassModelTags;
  63: 
  64: /**
  65:  * A model writer that writes to multiple files.
  66:  */
  67: public class SplittingModelWriter extends ModelWriter {
  68: 
  69:     /** ??. */
  70:     private HashNMap classDescriptionByPackage;
  71:     
  72:     /** The sources. */
  73:     private ArrayList sources;
  74:     
  75:     /** The target file. */
  76:     private File targetFile;
  77:     
  78:     /** The file extension. */
  79:     private String extension;
  80:     
  81:     /** The plain file name. */
  82:     private String plainFileName;
  83:     
  84:     /** ??. */
  85:     private HashNMap manualMappingByPackage;
  86:     
  87:     /** ??. */
  88:     private HashNMap multiplexMappingByPackage;
  89: 
  90:     /**
  91:      * Creates a new instance.
  92:      */
  93:     public SplittingModelWriter() {
  94:         super();
  95:     }
  96: 
  97:     /**
  98:      * Writes the model to the specified target.
  99:      * 
 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: }