package com.arsdigita.content; import java.lang.reflect.*; import java.sql.*; import java.util.*; import java.io.*; import oracle.sql.*; import oracle.xml.parser.v2.*; import oracle.jdbc.driver.*; import org.w3c.dom.*; import sqlj.runtime.ref.DefaultContext; import oracle.sqlj.runtime.Oracle; import org.xml.sax.SAXException; #sql iterator TypeIter(String object_type, String table_name, String id_column); #sql iterator AttrIter(String attribute_name); public class XMLExchange { public static void main(String[] args) throws Exception { Integer revisionID = new Integer(args[0]); PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(System.out))); exportRevision(revisionID, out); } public static int importRevision(Integer itemID, Integer revisionID, CLOB loc) throws SQLException, IOException, XMLParseException, SAXException { DOMParser parser = new DOMParser(); parser.parse(loc.getCharacterStream()); XMLDocument doc = parser.getDocument(); doc.print(System.out); XMLElement revision = (XMLElement) doc.getDocumentElement(); // Create the revision String title = getChildText(revision, "title"); String description = getChildText(revision, "description"); String publishDate = getChildText(revision, "publish_date"); String mimeType = getChildText(revision, "mime_type"); String text = getChildText(revision, "text"); #sql { begin :OUT revisionID := content_revision.new( title => :title, description => :description, publish_date => to_date(:publishDate), mime_type => :mimeType, text => :text, item_id => content_symlink.resolve(:itemID), revision_id => :revisionID); end; }; // Query for additional tables in which to insert extended attributes TypeIter typeIter; #sql typeIter = { select object_type, table_name, id_column from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = ( select object_type from acs_objects where object_id = :revisionID ) order by level desc }; String objectType; String dmlColumns, dmlValues; ArrayList attributes = new ArrayList(); AttrIter attrIter; // Use JDBC for the actual insert rather than SQLJ because we need // to build the DML dynamically Connection conn = DefaultContext.getDefaultContext().getConnection(); while (typeIter.next()) { objectType = typeIter.object_type(); dmlColumns = "insert into " + typeIter.table_name() + "(" + typeIter.id_column(); dmlValues = ") values ( ?"; // query the attributes of the table #sql attrIter = { select attribute_name from acs_attributes where object_type = :objectType order by attribute_name }; while (attrIter.next()) { dmlColumns += ", " + attrIter.attribute_name(); dmlValues += ",?"; attributes.add(attrIter.attribute_name()); } PreparedStatement stmt = conn.prepareStatement(dmlColumns + dmlValues + ")"); stmt.setInt(1, revisionID.intValue()); for (int i = 0; i < attributes.size(); i++) { stmt.setString(i + 2, getChildText(revision, (String) attributes.get(i))); } stmt.execute(); stmt.close(); attributes.clear(); } return revisionID.intValue(); } // Write XML to a CLOB public static int exportRevision(Integer revisionID, CLOB loc) throws SQLException, IOException { PrintWriter out = new PrintWriter(loc.getCharacterOutputStream()); exportRevision(revisionID, out); return revisionID.intValue(); } // Default implementation of a function to write an XML // representation of a content revision to an output stream. public static int exportRevision(Integer revisionID, PrintWriter out) throws SQLException { try { XMLDocument doc = new XMLDocument(); // get the content type String contentType; String tableName; String isContentType; #sql { select object_type, table_name, content_type.is_content_type(object_type) into :contentType, :tableName, :isContentType from acs_object_types where object_type = ( select object_type from acs_objects where object_id = :revisionID ) }; // screeen out non-content-types that are revisioned, such as templates if (isContentType.equals("f")) return -1; XMLElement revision = new XMLElement(contentType); doc.appendChild(revision); // select attributes for the revision AttrIter attrIter; #sql attrIter = { select attribute_name from ( select object_type, level sort_level from acs_object_types where object_type <> 'acs_object' start with object_type = :contentType connect by object_type = prior supertype ) types, acs_attributes attrs where attrs.object_type = types.object_type order by types.sort_level desc, attrs.sort_order }; // build the query to select attributes from the view for the // content type String attrQuery = "select revision_id"; while (attrIter.next()) { attrQuery += ", " + attrIter.attribute_name(); } attrQuery += " from " + tableName + "x where revision_id = ?"; // select a row from the attribute view for the content type Connection conn = DefaultContext.getDefaultContext().getConnection(); PreparedStatement stmt = conn.prepareStatement(attrQuery); stmt.setInt(1, revisionID.intValue()); ResultSet rs = stmt.executeQuery(); ResultSetMetaData md = rs.getMetaData(); if (rs.next()) { for (int i = 1; i <= md.getColumnCount(); i++) { // create an XML element for each attribute String colName = md.getColumnName(i); String colValue = rs.getString(i); if (colValue == null) colValue = ""; appendTextOnlyElement(revision, colName, colValue); } } stmt.close(); doc.print(out); } catch (Exception e) { throw new SQLException("Failed to generate XML document for revision " + revisionID + ": " + e); } return revisionID.intValue(); } private static String getChildText(XMLElement element, String name) { NodeList nodes = element.getChildrenByTagName(name); if (nodes.getLength() == 0) return null; // get the text node under this node Node textNode = nodes.item(0).getFirstChild(); return textNode.getNodeValue(); } private static void setChildText(XMLElement element, String text) { XMLText textNode = new XMLText(text); element.appendChild(textNode); } private static void appendTextOnlyElement(XMLElement parent, String name, String text) { XMLElement element = new XMLElement(name); setChildText(element, text); parent.appendChild(element); } }