package com.idega.util.xml; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.rmi.RemoteException; import java.util.zip.ZipInputStream; import org.jdom.IllegalDataException; import com.idega.core.file.data.ICFile; import com.idega.core.file.data.ICFileHome; import com.idega.data.IDOLookup; import com.idega.data.IDOStoreException; import com.idega.idegaweb.IWCacheManager; import com.idega.idegaweb.IWMainApplication; import com.idega.io.serialization.ObjectReader; import com.idega.io.serialization.ObjectWriter; import com.idega.io.serialization.Storable; import com.idega.presentation.IWContext; import com.idega.util.FileUtil; import com.idega.xml.XMLDocument; import com.idega.xml.XMLElement; import com.idega.xml.XMLException; import com.idega.xml.XMLOutput; import com.idega.xml.XMLParser; /** * <p>Title: idegaWeb</p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: idega Software</p> * @author <a href="thomas@idega.is">Thomas Hilbig</a> * @version 1.0 * Created on May 22, 2003 */ public class XMLData implements Storable { private final String DEFAULT_ROOT = "default_root"; public final String DEFAULT_NAME = "xml_data"; public final String AUXILIARY_FOLDER = "auxiliaryXMLDataFolder"; public final String AUXILIARY_FILE = "auxililary_xml_data_file_"; public final String XML_EXTENSION = ".xml"; private XMLDocument document = null; // xmlFileId and xmlFile are synchronized private int xmlFileId = -1; private ICFile xmlFile = null; private String name = null; private String rootName = null; public static XMLData getInstanceForInputStream(InputStream inputStream) throws IOException { XMLData data = new XMLData(); data.initialize(inputStream); return data; } public static XMLData getInstanceForInputStream(ZipInputStream zipInputStream) throws IOException { XMLData data = new XMLData(); data.initialize(zipInputStream); return data; } public static XMLData getInstanceForFile(int xmlFileId) throws IOException { XMLData data = new XMLData(); data.initialize(xmlFileId); return data; } public static XMLData getInstanceForFile(ICFile file) throws IOException { XMLData data = new XMLData(); data.initialize(file); return data; } public static XMLData getInstanceForFile(String path) throws IOException { XMLData data = new XMLData(); data.initialize(path); return data; } public static XMLData getInstanceForFile(File file) throws IOException { XMLData data = new XMLData(); data.initialize(file); return data; } public static XMLData getInstanceWithoutExistingFile() { XMLData data = new XMLData(); return data; } public static XMLData getInstanceWithoutExistingFileSetName(String name) { XMLData data = XMLData.getInstanceWithoutExistingFile(); data.setName(name); return data; } public static XMLData getInstanceWithoutExistingFileSetNameSetRootName(String name, String rootName) { XMLData data = getInstanceWithoutExistingFileSetName(name); data.rootName = rootName; return data; } public void initialize(int fileId) throws IOException { ICFile tempXmlFile = getXMLFile(fileId); initialize(tempXmlFile); } public String getName() { // name is set if (this.name != null && this.name.length() > 0) { return this.name; } // name is not set, file id is set if (this.xmlFileId > -1) { StringBuffer buffer = new StringBuffer(this.DEFAULT_NAME); buffer.append('_').append(this.xmlFileId); return buffer.toString(); } // neither name nor file id is set return this.DEFAULT_NAME; } public void setName(String name) { this.name = name; } public XMLDocument getDocument() { if (this.document == null) { // create an empty document String tempRootName = (this.rootName == null) ? this.DEFAULT_ROOT : this.rootName; this.document = new XMLDocument(new XMLElement(tempRootName)); } return this.document; } public void setDocument(XMLDocument document) { this.document = document; } public ICFile store() throws IOException { // create or fetch existing ICFile ICFile tempXmlFile = (this.xmlFileId < 0) ? getNewXMLFile() : getXMLFile(this.xmlFileId); tempXmlFile.setMimeType("text/xml"); tempXmlFile.setName(getName()); try { tempXmlFile.store(); } catch (IDOStoreException ex) { System.err.println("[XMLData] problem storing ICFile Message is: "+ex.getMessage()); ex.printStackTrace(System.err); throw new IOException("xml file could not be stored"); } if (this.xmlFileId < 0) { this.xmlFileId = ((Integer)tempXmlFile.getPrimaryKey()).intValue(); // the default name uses the id, therefore set again and store again if (this.name == null) { tempXmlFile.setName(getName()); } } // To avoid problems with databases (e.g. MySQL) // we do not write directly to the ICFile object but // create an auxiliary file on the hard disk and write the xml file to that file. // After that we read the file on the hard disk an write it to the ICFile object. // Finally we delete the auxiliary file. // write the output first to a file object // get the output stream String separator = FileUtil.getFileSeparator(); IWMainApplication mainApp = IWContext.getInstance().getIWMainApplication(); StringBuffer path = new StringBuffer(mainApp.getApplicationRealPath()); path.append(IWCacheManager.IW_ROOT_CACHE_DIRECTORY) .append(separator) .append(this.AUXILIARY_FOLDER); // check if the folder exists create it if necessary // usually the folder should be already be there. // the folder is never deleted by this class FileUtil.createFolder(path.toString()); // set name of auxiliary file path.append(separator).append(this.AUXILIARY_FILE).append(this.xmlFileId).append(this.XML_EXTENSION); File auxiliaryFile = new File(path.toString()); writeToFile(auxiliaryFile); //writing finished // get size of the file int size = (int) auxiliaryFile.length(); // get the input stream of the auxiliary file BufferedInputStream inputStream = null; try { inputStream = new BufferedInputStream(new FileInputStream(auxiliaryFile)); } catch (FileNotFoundException ex) { System.err.println("[XMLData] problem reading file. Message is: "+ex.getMessage()); ex.printStackTrace(System.err); throw new IOException("xml file could not be stored"); } // now we have an input stream of the auxiliary file // write to the ICFile object tempXmlFile.setFileSize(size); try { tempXmlFile.setFileValue(inputStream); tempXmlFile.store(); } finally { close(inputStream); } // try { //xmlFile.update(); // } // catch (SQLException ex) { // System.err.println("[XMLData] problem storing ICFile Message is: "+ex.getMessage()); // ex.printStackTrace(System.err); // throw new IOException("xml file could not be stored"); // } // reading finished // delete file auxiliaryFile.delete(); return tempXmlFile; } private void initialize(ICFile aXmlFile) throws IOException { this.name = aXmlFile.getName(); setXmlFile(aXmlFile); InputStream inputStream = aXmlFile.getFileValue(); initialize(inputStream); } private void initialize(ZipInputStream inputStream) throws IOException { // do not close zip input streams try { XMLParser parser = new XMLParser(); this.document = parser.parse(inputStream); } catch (IllegalDataException illEx) { this.document = null; this.xmlFileId = -1; throw new IOException("[XMLData] input stream could not be parsed because of some illegal data within the data. Message is: " + illEx.getMessage()); } catch (XMLException ex) { this.document = null; this.xmlFileId = -1; throw new IOException("[XMLData] input stream could not be parsed. Message is: " + ex.getMessage()); } } public void initialize(InputStream inputStream) throws IOException { try { XMLParser parser = new XMLParser(); this.document = parser.parse(inputStream); } catch (IllegalDataException illEx) { this.document = null; this.xmlFileId = -1; throw new IOException("[XMLData] input stream could not be parsed because of some illegal data within the data. Message is: " + illEx.getMessage()); } catch (XMLException ex) { this.document = null; this.xmlFileId = -1; throw new IOException("[XMLData] input stream could not be parsed. Message is: " + ex.getMessage()); } finally { close(inputStream); } } private void initialize(String path) throws IOException { File file = new File(path); if (! (file.exists() && file.canRead() && file.isFile())) { throw new IOException("[XMLData] File: " + path + " could not be opened"); } initialize(file); } private void initialize(File file) throws IOException { InputStream inputStream = null; try { inputStream = new BufferedInputStream(new FileInputStream(file)); } catch(FileNotFoundException ex) { close(inputStream); throw ex; } try { initialize(inputStream); } catch (IOException ex) { String message = ex.getMessage(); message = "File: \"" + file.getPath() + "\" caused exception: " + message; throw new IOException(message); } } private ICFile getXMLFile(int fileId) { if (this.xmlFile != null) { return this.xmlFile; } try { ICFileHome home = (ICFileHome) IDOLookup.getHome(ICFile.class); ICFile tempXmlFile = home.findByPrimaryKey(new Integer(fileId)); return tempXmlFile; } // FinderException, RemoteException catch(Exception ex){ System.err.println("[XMLData]: Can't retrieve file with id "+ fileId + "Message is:" + ex.getMessage()); ex.printStackTrace(System.err); return null; } } private ICFile getNewXMLFile() { try { ICFileHome home = (ICFileHome) IDOLookup.getHome(ICFile.class); ICFile tempXmlFile = home.create(); return tempXmlFile; } // FinderException, RemoteException catch (Exception ex) { throw new RuntimeException("[XMLData]: Message was: " + ex.getMessage()); } } private void close(InputStream input) { try { if (input != null) { input.close(); } } catch (IOException io) { // do not hide an existing exception } } private void close(OutputStream output) { try { if (output != null) { output.close(); } } catch (IOException io) { // do not hide an existing exception } } /** * @return */ public int getXmlFileId() { return this.xmlFileId; } /** * @param i */ public void setXmlFileId(int i) { this.xmlFileId = i; // check existing file if ((this.xmlFile != null) && (((Integer)this.xmlFile.getPrimaryKey()).intValue() != i)) { // different file is set therefore set existing xmlFile to null this.xmlFile = null; } } public void setXmlFile(ICFile file) { this.xmlFile = file; this.xmlFileId = ((Integer)this.xmlFile.getPrimaryKey()).intValue(); } public Object write(ObjectWriter writer, IWContext iwc) throws RemoteException { return writer.write(this, iwc); } public Object read(ObjectReader reader, IWContext iwc) throws RemoteException { return reader.read(this, iwc); } public void add(XMLData data) { XMLElement dataRootElement = data.getDocument().getRootElement(); dataRootElement = dataRootElement.detach(); getDocument().getRootElement().addContent(dataRootElement); } public void writeToFile(File output) throws IOException { BufferedOutputStream outputStream = null; try { outputStream = new BufferedOutputStream(new FileOutputStream(output)); } catch (FileNotFoundException ex) { System.err.println("[XMLData] problem creating file. Message is: "+ex.getMessage()); ex.printStackTrace(System.err); throw new IOException("xml file could not be stored"); } // now we have an output stream of the auxiliary file // write to the xml file XMLOutput xmlOutput = new XMLOutput(" ", true); xmlOutput.setLineSeparator(System.getProperty("line.separator")); xmlOutput.setTextNormalize(true); //xmlOutput.setEncoding("iso-8859-1"); xmlOutput.setEncoding("UTF-8"); // do not use document directly use accessor method XMLDocument myDocument = getDocument(); try { xmlOutput.output(myDocument, outputStream); } finally { close(outputStream); } } }