001 /* 002 Copyright (C) 2003-2004 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.aspects.export; 019 020 import gnu.regexp.RE; 021 import java.io.FileOutputStream; 022 import java.io.IOException; 023 import java.io.OutputStream; 024 import java.io.OutputStreamWriter; 025 import java.io.Writer; 026 import java.lang.StringBuffer; 027 import java.util.Collection; 028 import java.util.HashMap; 029 import java.util.HashSet; 030 import java.util.Iterator; 031 import java.util.Map; 032 import java.util.Set; 033 import org.apache.log4j.Logger; 034 import org.objectweb.jac.aspects.naming.NamingAC; 035 import org.objectweb.jac.aspects.persistence.ValueConverter; 036 import org.objectweb.jac.core.ACManager; 037 import org.objectweb.jac.core.NameRepository; 038 import org.objectweb.jac.core.Wrappee; 039 import org.objectweb.jac.core.rtti.ClassItem; 040 import org.objectweb.jac.core.rtti.ClassRepository; 041 import org.objectweb.jac.core.rtti.CollectionItem; 042 import org.objectweb.jac.core.rtti.FieldItem; 043 import org.objectweb.jac.util.Strings; 044 import java.io.File; 045 046 public class Exporter { 047 static Logger logger = Logger.getLogger("export"); 048 049 Set roots = new HashSet(); 050 Set allow = new HashSet(); 051 Set deny = new HashSet(); 052 053 Set allowRegexps = new HashSet(); 054 Set denyRegexps = new HashSet(); 055 056 Map toExport = new HashMap(); // Objects not exported yet (OPath -> Object) 057 Set exported = new HashSet(); // Already exported objects 058 059 060 NameRepository nr; 061 public Exporter(Set roots, Set allow, Set deny) { 062 nr = (NameRepository)NameRepository.get(); 063 this.roots = roots; 064 this.allow = allow; 065 Iterator i = allow.iterator(); 066 while (i.hasNext()) { 067 String s = (String)i.next(); 068 try { 069 RE regexp = new RE(s); 070 allowRegexps.add(regexp); 071 } catch (Exception e) { 072 e.printStackTrace(); 073 } 074 } 075 this.deny = deny; 076 i = deny.iterator(); 077 while (i.hasNext()) { 078 String s = (String)i.next(); 079 try { 080 RE regexp = new RE(s); 081 denyRegexps.add(regexp); 082 } catch (Exception e) { 083 e.printStackTrace(); 084 } 085 } 086 } 087 088 /** 089 * Exports all objects to a file 090 */ 091 public void export(File file) throws IOException { 092 FileOutputStream out = new FileOutputStream(file); 093 try { 094 export(out); 095 } finally { 096 out.close(); 097 } 098 } 099 100 public void export(OutputStream outStream) throws IOException { 101 export(outStream,"UTF-8"); 102 } 103 104 /** 105 * Exports all objects to a stream 106 */ 107 public void export(OutputStream outStream, String encoding) throws IOException { 108 Writer out = new OutputStreamWriter(outStream,encoding); 109 out.write("<?xml version=\"1.0\" encoding=\""+encoding+"\"?>\n"); 110 out.write("<export>\n"); 111 int count = 0; 112 Iterator i = NameRepository.getObjects(roots).iterator(); 113 while (i.hasNext()) { 114 Object o = i.next(); 115 String name = nr.getName(o); 116 export(out,o,name,name); 117 count++; 118 } 119 while (!toExport.isEmpty()) { 120 i = new HashMap(toExport).entrySet().iterator(); 121 while (i.hasNext()) { 122 Map.Entry entry = (Map.Entry)i.next(); 123 Object o = entry.getKey(); 124 String opath = (String)entry.getValue(); 125 String name = nr.getName(o); 126 export(out,o,name,opath); 127 count++; 128 } 129 } 130 logger.info(count+" objects exported"); 131 Map counters = 132 ((NamingAC)ACManager.getACM().getACFromFullName("naming")).getNameCounters(); 133 i = counters.entrySet().iterator(); 134 while(i.hasNext()) { 135 Map.Entry entry = (Map.Entry)i.next(); 136 out.write("<nameCounter>\n"); 137 out.write("<name>"+entry.getKey()+"</name>\n"); 138 out.write("<counter>"+entry.getValue()+"</counter>\n"); 139 out.write("</nameCounter>\n"); 140 } 141 logger.info("Name counters exported"); 142 out.write("</export>\n"); 143 out.flush(); 144 } 145 146 static public String escapeChar(char c) { 147 return (c == '<') ? "<" : 148 (c == '>') ? ">" : 149 (c == '\'') ? "'" : 150 (c == '\"') ? """ : 151 (c == '&') ? "&" : 152 (c == ']') ? "]" : 153 //(c == '\n') ? " " : 154 //(c == '\r') ? " " : 155 null; 156 } 157 158 static public String escapeString(String s) { 159 StringBuffer buf = new StringBuffer(s.length()*2); 160 for (int i=0; i<s.length(); i++) { 161 char c = s.charAt(i); 162 String escaped = escapeChar(c); 163 if (escaped==null) 164 buf.append(c); 165 else 166 buf.append(escaped); 167 } 168 return buf.toString(); 169 } 170 171 /** 172 * Tells wether instances of a class should be exported or not 173 */ 174 protected boolean allowExport(ClassItem cl) { 175 Iterator i = allowRegexps.iterator(); 176 while(i.hasNext()) { 177 RE regexp = (RE)i.next(); 178 if (cl.isSubClassOf(regexp)) 179 return true; 180 } 181 return false; 182 } 183 184 /** 185 * Exports an object to a stream 186 * @param out the stream to which to export 187 * @param o the object to export 188 * @param name name of the object to export 189 */ 190 public void export(Writer out, Object o, String name ,String opath) throws IOException { 191 ClassItem cl = ClassRepository.get().getClass(o); 192 if (name==null) { 193 logger.error("Skipping unamed object "+o+" "+cl.getName()+" at "+opath); 194 new Exception().printStackTrace(); 195 toExport.remove(o); 196 return; 197 } 198 if (exported.contains(o)) { 199 logger.debug("Skipping already exported "+name+" "+cl.getName()); 200 toExport.remove(o); 201 return; 202 } 203 if (!allowExport(cl)) { 204 logger.debug("Skipping not allowed "+name+" "+cl.getName()); 205 toExport.remove(o); 206 return; 207 } 208 logger.debug("Exporting "+name+" "+cl.getName()); 209 exported.add(o); 210 out.write("<object name=\""+name+"\" class=\""+cl.getName()+"\">\n"); 211 Iterator i = cl.getAllFields().iterator(); 212 while (i.hasNext()) { 213 FieldItem field = (FieldItem)i.next(); 214 if (!field.isCalculated() && !field.isTransient() && 215 !field.isStatic() && !field.isTransient()) 216 { 217 String newPath = opath+"."+field.getName(); 218 Object value = field.getThroughAccessor(o); 219 out.write(" <field name=\""+field.getName()+"\">\n"); 220 try { 221 if (field instanceof CollectionItem) { 222 CollectionItem collection = (CollectionItem)field; 223 if (collection.isMap()) { 224 out.write(" <map>\n"); 225 Iterator j = ((Map)collection.getThroughAccessor(o)).entrySet().iterator(); 226 while (j.hasNext()) { 227 Map.Entry entry = (Map.Entry)j.next(); 228 out.write(" <entry><key>"); 229 writeValue(out,entry.getKey(),newPath+"[key]"); 230 out.write("</key><value>"); 231 writeValue(out,entry.getValue(),newPath+"["+entry.getKey()+"]"); 232 out.write("</value></entry>\n"); 233 } 234 out.write(" </map>\n"); 235 } else { 236 if (collection.isList()) 237 out.write(" <list>\n"); 238 else if (collection.isSet()) 239 out.write(" <set>\n"); 240 Iterator j = ((Collection)collection.getThroughAccessor(o)).iterator(); 241 int count = 0; 242 while (j.hasNext()) { 243 Object item = j.next(); 244 out.write(" "); 245 writeValue(out,item,newPath+"["+count+"]"); 246 out.write("\n"); 247 count++; 248 } 249 if (collection.isList()) 250 out.write(" </list>\n"); 251 else if (collection.isSet()) 252 out.write(" </set>\n"); 253 } 254 } else { 255 out.write(" "); 256 writeValue(out,value,newPath); 257 out.write("\n"); 258 } 259 } catch (Exception e) { 260 logger.error("Failed to export "+name+"."+field); 261 } finally { 262 out.write(" </field>\n"); 263 } 264 } 265 } 266 out.write("</object>\n"); 267 } 268 269 protected void writeValue(Writer out, Object value, String opath) throws IOException { 270 if (value instanceof Wrappee) { 271 if (value!=null) { 272 if (!exported.contains(value)) { 273 toExport.put(value,opath); 274 logger.debug("toExport "+opath+" -> "+value+" "+nr.getName(value)); 275 } 276 out.write("<reference>"+nr.getName(value)+"</reference>"); 277 } else { 278 out.write("<reference>null</reference>"); 279 } 280 } else { 281 if (value!=null) { 282 out.write("<primitive_value>"+ 283 escapeString(Strings.slashify(ValueConverter.objectToString(null,value)))+ 284 "</primitive_value>"); 285 } else { 286 out.write("<primitive_value>null</primitive_value>"); 287 } 288 } 289 } 290 }