Index: components/page-manager/src/test/org/apache/jetspeed/page/TestCastorXmlPageManager.java =================================================================== --- components/page-manager/src/test/org/apache/jetspeed/page/TestCastorXmlPageManager.java (revision 548244) +++ components/page-manager/src/test/org/apache/jetspeed/page/TestCastorXmlPageManager.java (working copy) @@ -28,6 +28,7 @@ import junit.framework.TestCase; import junit.framework.TestSuite; +import org.apache.commons.collections.CollectionUtils; import org.apache.jetspeed.JetspeedActions; import org.apache.jetspeed.om.common.GenericMetadata; import org.apache.jetspeed.om.common.SecurityConstraint; @@ -967,4 +968,34 @@ // TODO: menu testing } + + public Collection collectIds(Fragment f){ + Collection result = new ArrayList(); + + result.add(f.getId()); + if (f.getFragments().size() > 0){ + for (Iterator iter = f.getFragments().iterator(); iter.hasNext();) { + Fragment child = (Fragment) iter.next(); + result.addAll(collectIds(child)); + } + } + return result; + } + + public void testIdGeneration() throws Exception{ + Page pageNoIds = pageManager.getPage("/pageWithoutIds.psml"); + assertNotNull(pageNoIds); + Page pageSomeIds = pageManager.getPage("/pageWithSomeIds.psml"); + assertNotNull(pageSomeIds); + + Collection allIds = collectIds(pageNoIds.getRootFragment()); + allIds.addAll(collectIds(pageSomeIds.getRootFragment())); + for (Iterator iter = allIds.iterator(); iter.hasNext();) { + String id = (String) iter.next(); + assertNotNull(id); + assertEquals(true,id.length() > 0); + assertEquals(1, CollectionUtils.cardinality(id, allIds)); // uniqueness test + } + } + } Index: components/page-manager/src/java/org/apache/jetspeed/om/page/psml/FragmentImpl.java =================================================================== --- components/page-manager/src/java/org/apache/jetspeed/om/page/psml/FragmentImpl.java (revision 548244) +++ components/page-manager/src/java/org/apache/jetspeed/om/page/psml/FragmentImpl.java (working copy) @@ -36,6 +36,8 @@ public class FragmentImpl extends AbstractBaseElement implements Fragment, java.io.Serializable { + private static int fragment_id_counter = 0; + private String type = null; private String state = null; @@ -69,6 +71,15 @@ { } + public FragmentImpl(String id) + { + if (id == null || id.length() == 0){ + setId(generateId()); + } else { + setId(id); + } + } + public String getType() { return this.type; @@ -689,4 +700,8 @@ } return fragments; } + + private synchronized static String generateId(){ + return new StringBuffer("F.").append(Long.toHexString(System.currentTimeMillis())).append(".").append(fragment_id_counter++).toString(); + } } Index: components/page-manager/src/java/org/apache/jetspeed/page/document/psml/CastorFileSystemDocumentHandler.java =================================================================== --- components/page-manager/src/java/org/apache/jetspeed/page/document/psml/CastorFileSystemDocumentHandler.java (revision 548244) +++ components/page-manager/src/java/org/apache/jetspeed/page/document/psml/CastorFileSystemDocumentHandler.java (working copy) @@ -49,20 +49,25 @@ import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.Serializer; import org.apache.xml.serialize.XMLSerializer; +import org.castor.mapping.BindingType; +import org.castor.mapping.MappingUnmarshaller; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.mapping.MappingException; -import org.exolab.castor.xml.EventProducer; +import org.exolab.castor.mapping.MappingLoader; +import org.exolab.castor.xml.ClassDescriptorResolver; +import org.exolab.castor.xml.ClassDescriptorResolverFactory; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.Marshaller; +import org.exolab.castor.xml.SAX2EventProducer; import org.exolab.castor.xml.Unmarshaller; import org.exolab.castor.xml.ValidationException; -import org.xml.sax.AttributeList; -import org.xml.sax.DocumentHandler; +import org.exolab.castor.xml.XMLClassDescriptorResolver; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; -import org.xml.sax.helpers.XMLReaderAdapter; /** *

@@ -81,19 +86,16 @@ private final static Log log = LogFactory.getLog(CastorFileSystemDocumentHandler.class); private final static String PSML_DOCUMENT_ENCODING = "UTF-8"; - - protected String mappingFile; protected String documentType; protected Class expectedReturnType; protected String documentRoot; protected File documentRootDir; protected FileCache fileCache; - /** the Castor mapping file name */ - protected Mapping mapping = null; - + private OutputFormat format; - + private final XMLReader xmlReader; private DocumentHandlerFactory handlerFactory; + private ClassDescriptorResolver classDescriptorResolver; /** * @@ -105,10 +107,9 @@ * @throws FileNotFoundException */ public CastorFileSystemDocumentHandler( String mappingFile, String documentType, Class expectedReturnType, - String documentRoot, FileCache fileCache ) throws FileNotFoundException + String documentRoot, FileCache fileCache ) throws FileNotFoundException,SAXException,ParserConfigurationException, MappingException { super(); - this.mappingFile = mappingFile; this.documentType = documentType; this.expectedReturnType = expectedReturnType; this.documentRoot = documentRoot; @@ -120,12 +121,22 @@ format.setIndenting(true); format.setIndent(4); format.setEncoding(PSML_DOCUMENT_ENCODING); - - loadMapping(); + + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser parser = factory.newSAXParser(); + + xmlReader = parser.getXMLReader(); + xmlReader.setFeature("http://xml.org/sax/features/namespaces", true); + + /* + * Create ClassDescripterResolver for better performance. + * Mentioned as 'best practice' on the Castor website. + */ + createCastorClassDescriptorResolver(mappingFile); } public CastorFileSystemDocumentHandler( String mappingFile, String documentType, String expectedReturnType, - String documentRoot, FileCache fileCache ) throws FileNotFoundException, ClassNotFoundException + String documentRoot, FileCache fileCache ) throws FileNotFoundException, ClassNotFoundException,SAXException,ParserConfigurationException, MappingException { this(mappingFile, documentType, Class.forName(expectedReturnType), documentRoot, fileCache); } @@ -191,17 +202,18 @@ try { - // marshal: use SAX I handler to filter document XML for + // marshal: use SAX II handler to filter document XML for // page and folder menu definition menu elements ordered // polymorphic collection to strip artifical // tags enabling Castor XML binding; see JETSPEED-INF/castor/page-mapping.xml writer = new OutputStreamWriter(new FileOutputStream(f), PSML_DOCUMENT_ENCODING); Serializer serializer = new XMLSerializer(writer, this.format); - final DocumentHandler handler = serializer.asDocumentHandler(); - Marshaller marshaller = new Marshaller(new DocumentHandler() + final ContentHandler handler = serializer.asContentHandler(); + + Marshaller marshaller = new Marshaller(new ContentHandler() { private int menuDepth = 0; - + public void characters(char[] ch, int start, int length) throws SAXException { handler.characters(ch, start, length); @@ -212,21 +224,6 @@ handler.endDocument(); } - public void endElement(String name) throws SAXException - { - // track menu depth - if (name.equals("menu")) - { - menuDepth--; - } - - // filter menu-element noded within menu definition - if ((menuDepth == 0) || !name.equals("menu-element")) - { - handler.endElement(name); - } - } - public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { handler.ignorableWhitespace(ch, start, length); @@ -247,22 +244,49 @@ handler.startDocument(); } - public void startElement(String name, AttributeList atts) throws SAXException - { + public void endElement(String uri, String localName, String qName) throws SAXException { + // track menu depth + if (localName.equals("menu")) + { + menuDepth--; + } + // filter menu-element noded within menu definition - if ((menuDepth == 0) || !name.equals("menu-element")) + if ((menuDepth == 0) || !localName.equals("menu-element")) { - handler.startElement(name, atts); + handler.endElement(uri, localName, qName); } + } + public void endPrefixMapping(String prefix) throws SAXException { + handler.endPrefixMapping(prefix); + } + + public void skippedEntity(String name) throws SAXException { + handler.skippedEntity(name); + } + + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + // filter menu-element noded within menu definition + if ((menuDepth == 0) || !localName.equals("menu-element")) + { + handler.startElement(uri,localName, qName, atts); + } + // track menu depth - if (name.equals("menu")) + if (localName.equals("menu")) { menuDepth++; } - } + } + + public void startPrefixMapping(String prefix, String uri) throws SAXException { + handler.startPrefixMapping(prefix, uri); + } }); - marshaller.setMapping(this.mapping); + marshaller.setResolver((XMLClassDescriptorResolver) classDescriptorResolver); + + marshaller.setValidation(false); // results in better performance marshaller.marshal(document); } catch (MarshalException e) @@ -270,11 +294,6 @@ log.error("Could not marshal the file " + f.getAbsolutePath(), e); throw new FailedToUpdateDocumentException(e); } - catch (MappingException e) - { - log.error("Could not marshal the file " + f.getAbsolutePath(), e); - throw new FailedToUpdateDocumentException(e); - } catch (ValidationException e) { log.error("Document " + f.getAbsolutePath() + " is not valid", e); @@ -303,11 +322,10 @@ } - - - protected void loadMapping() + protected void createCastorClassDescriptorResolver(String mappingFile) throws MappingException { - try + Mapping mapping=null; + try { InputStream stream = getClass().getResourceAsStream(mappingFile); @@ -329,7 +347,11 @@ ise.initCause(e); throw ise; } - + this.classDescriptorResolver = + ClassDescriptorResolverFactory.createClassDescriptorResolver(BindingType.XML); + MappingUnmarshaller mappingUnmarshaller = new MappingUnmarshaller(); + MappingLoader mappingLoader = mappingUnmarshaller.getMappingLoader(mapping, BindingType.XML); + classDescriptorResolver.setMappingLoader(mappingLoader); } protected Object unmarshallDocument( Class clazz, String path, String extension ) throws DocumentNotFoundException, @@ -353,21 +375,20 @@ try { - // unmarshal: use SAX I parser to read document XML, filtering + // unmarshal: use SAX II parser to read document XML, filtering // for page and folder menu definition menu elements ordered // polymorphic collection to insert artifical // tags enabling Castor XML binding; see JETSPEED-INF/castor/page-mapping.xml - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser parser = factory.newSAXParser(); - XMLReader reader = parser.getXMLReader(); - final XMLReaderAdapter readerAdapter = new XMLReaderAdapter(reader); + final InputSource readerInput = new InputSource(new InputStreamReader(new FileInputStream(f), PSML_DOCUMENT_ENCODING)); - Unmarshaller unmarshaller = new Unmarshaller(this.mapping); - document = (Document) unmarshaller.unmarshal(new EventProducer() + Unmarshaller unmarshaller = new Unmarshaller(); + unmarshaller.setResolver((XMLClassDescriptorResolver) classDescriptorResolver); + unmarshaller.setValidation(false); // results in better performance + document = (Document) unmarshaller.unmarshal(new SAX2EventProducer() { - public void setDocumentHandler(final DocumentHandler handler) + public void setContentHandler(final ContentHandler handler) { - readerAdapter.setDocumentHandler(new DocumentHandler() + xmlReader.setContentHandler(new ContentHandler() { private int menuDepth = 0; @@ -381,30 +402,6 @@ handler.endDocument(); } - public void endElement(String name) throws SAXException - { - // always include all elements - handler.endElement(name); - - // track menu depth and insert menu-element nodes - // to encapsulate menu elements to support collection - // polymorphism in Castor - if (name.equals("menu")) - { - menuDepth--; - if (menuDepth > 0) - { - handler.endElement("menu-element"); - } - } - else if ((menuDepth > 0) && - (name.equals("options") || name.equals("separator") || - name.equals("include") || name.equals("exclude"))) - { - handler.endElement("menu-element"); - } - } - public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { handler.ignorableWhitespace(ch, start, length); @@ -425,36 +422,72 @@ handler.startDocument(); } - public void startElement(String name, AttributeList atts) throws SAXException - { + public void endElement(String uri, String localName, String qName) throws SAXException { +// always include all elements + uri=""; // strip namespaces + + handler.endElement(uri,localName,qName); // track menu depth and insert menu-element nodes // to encapsulate menu elements to support collection // polymorphism in Castor - if (name.equals("menu")) + if (localName.equals("menu")) { + menuDepth--; if (menuDepth > 0) { - handler.startElement("menu-element", null); + handler.endElement(uri,"menu-element","menu-element"); } + } + else if ((menuDepth > 0) && + (localName.equals("options") || localName.equals("separator") || + localName.equals("include") || localName.equals("exclude"))) + { + handler.endElement(uri,"menu-element","menu-element"); + } + } + + public void endPrefixMapping(String prefix) throws SAXException { + handler.endPrefixMapping(prefix); + } + + public void skippedEntity(String name) throws SAXException { + handler.skippedEntity(name); + } + + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + // track menu depth and insert menu-element nodes + // to encapsulate menu elements to support collection + // polymorphism in Castor + uri=""; // strip namespaces + if (localName.equals("menu")) + { + if (menuDepth > 0) + { + handler.startElement(uri,"menu-element","menu-element", null); + } menuDepth++; } else if ((menuDepth > 0) && - (name.equals("options") || name.equals("separator") || - name.equals("include") || name.equals("exclude"))) + (localName.equals("options") || localName.equals("separator") || + localName.equals("include") || localName.equals("exclude"))) { - handler.startElement("menu-element", null); + handler.startElement(uri,"menu-element","menu-element", null); } // always include all elements - handler.startElement(name, atts); - } + handler.startElement(uri,localName, qName, atts); + } + + public void startPrefixMapping(String prefix, String uri) throws SAXException { + handler.startPrefixMapping(prefix, uri); + } }); } public void start() throws SAXException { try { - readerAdapter.parse(readerInput); + xmlReader.parse(readerInput); } catch (IOException ioe) { @@ -480,26 +513,11 @@ log.error("Could not unmarshal the file " + f.getAbsolutePath(), e); throw new PageNotFoundException("Could not unmarshal the file " + f.getAbsolutePath(), e); } - catch (MappingException e) - { - log.error("Could not unmarshal the file " + f.getAbsolutePath(), e); - throw new PageNotFoundException("Could not unmarshal the file " + f.getAbsolutePath(), e); - } catch (ValidationException e) { log.error("Document " + f.getAbsolutePath() + " is not valid", e); throw new DocumentNotFoundException("Document " + f.getAbsolutePath() + " is not valid", e); } - catch (SAXException e) - { - log.error("Could not unmarshal the file " + f.getAbsolutePath(), e); - throw new PageNotFoundException("Could not unmarshal the file " + f.getAbsolutePath(), e); - } - catch (ParserConfigurationException e) - { - log.error("Could not unmarshal the file " + f.getAbsolutePath(), e); - throw new PageNotFoundException("Could not unmarshal the file " + f.getAbsolutePath(), e); - } if (document == null) Index: components/page-manager/src/java/JETSPEED-INF/castor/page-mapping.xml =================================================================== --- components/page-manager/src/java/JETSPEED-INF/castor/page-mapping.xml (revision 548244) +++ components/page-manager/src/java/JETSPEED-INF/castor/page-mapping.xml (working copy) @@ -1,5 +1,5 @@ - castor - - 0.9.4.3 + 1.1.1-xml true