package org.codehaus.mojo.gwt.webxml;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.codehaus.plexus.util.WriterFactory;
import org.jdom.Comment;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;
/**
* @version $Id$
*/
public class GwtWebInfProcessor
{
private static final String[] BEFORE_SERVLETS =
{ "icon", "display-name", "description", "distributable", "context-param", "filter", "filter-mapping",
"listener", "servlet" };
private static final String[] AFTER_SERVLETS =
{ "servlet-mapping", "session-config", "mime-mapping", "welcome-file-list", "error-page", "taglib",
"resource-env-ref", "resource-ref", "security-constraint", "login-config", "security-role", "env-entry",
"ejb-ref", "ejb-local-ref" };
private static final String[] BEFORE_MAPPINGS =
{ "icon", "display-name", "description", "distributable", "context-param", "filter", "filter-mapping",
"listener", "servlet", "servlet-mapping" };
private static final String[] AFTER_MAPPINGS =
{ "session-config", "mime-mapping", "welcome-file-list", "error-page", "taglib", "resource-env-ref",
"resource-ref", "security-constraint", "login-config", "security-role", "env-entry", "ejb-ref",
"ejb-local-ref" };
public void process( File webXml, Collection<ServletDescriptor> servletDescriptors )
throws Exception
{
process( webXml, webXml, servletDescriptors );
}
public void process( File sourceWebXml, File mergeWebXml, Collection<ServletDescriptor> servletDescriptors )
throws Exception
{
Document dom = insertServlets( sourceWebXml, servletDescriptors );
XMLOutputter xmlOut = new XMLOutputter( Format.getPrettyFormat() );
Writer writer = WriterFactory.newXmlWriter( mergeWebXml );
xmlOut.output( dom, writer );
writer.flush();
writer.close();
}
private Document insertServlets( File webXml, Collection<ServletDescriptor> servletDescriptors )
throws JDOMException, IOException
{
/*
* <!ELEMENT web-app (icon?, display-name?, description?, distributable?, context-param*, filter*,
* filter-mapping*, listener*, servlet*, servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?,
* error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*, login-config?, security-role*,
* env-entry*, ejb-ref*, ejb-local-ref*)>
*/
Document dom = getWebXmlAsDocument( webXml );
Element webapp = dom.getRootElement();
Namespace ns = webapp.getNamespace();
int insertAfter = getInsertPosition( webapp, BEFORE_SERVLETS, AFTER_SERVLETS );
for ( Iterator<ServletDescriptor> it = servletDescriptors.iterator(); it.hasNext(); )
{
ServletDescriptor d = it.next();
XPath path = XPath.newInstance( "/web-app/servlet/servlet-name[text() = '" + d.getName() + "']" );
if ( path.selectNodes( dom ).size() > 0 )
{
// Allready declared in target web.xml
it.remove();
continue;
}
insertAfter++;
Element servlet = new Element( "servlet", ns );
Element servletName = new Element( "servlet-name", ns );
servletName.setText( d.getName() );
servlet.addContent( servletName );
Element servletClass = new Element( "servlet-class", ns );
servletClass.setText( d.getClassName() );
servlet.addContent( servletClass );
webapp.addContent( insertAfter, servlet );
}
insertAfter = getInsertPosition( webapp, BEFORE_MAPPINGS, AFTER_MAPPINGS );
for ( ServletDescriptor d : servletDescriptors )
{
insertAfter++;
Element servletMapping = new Element( "servlet-mapping", ns );
Element servletName = new Element( "servlet-name", ns );
servletName.setText( d.getName() );
servletMapping.addContent( servletName );
Element urlPattern = new Element( "url-pattern", ns );
String path = d.getPath();
if ( path.charAt( 0 ) != '/' )
{
path = '/' + path;
}
urlPattern.setText( path );
servletMapping.addContent( urlPattern );
webapp.addContent( insertAfter, servletMapping );
}
return dom;
}
private int getInsertPosition( Element webapp, String[] startAfter, String[] stopBefore )
throws JDOMException, IOException
{
List children = webapp.getContent();
Content insertAfter = new Comment( "inserted by gwt-maven-plugin" );
ArrayList<String> namesBefore = new ArrayList<String>();
ArrayList<String> namesAfter = new ArrayList<String>();
for ( int i = 0; i < startAfter.length; i++ )
{
namesBefore.add( startAfter[i] );
}
for ( int i = 0; i < stopBefore.length; i++ )
{
namesAfter.add( stopBefore[i] );
}
if ( ( children == null ) || ( children.size() == 0 ) )
{
webapp.addContent( insertAfter );
}
else
{
boolean foundPoint = false;
for ( int i = 0; !foundPoint && i < children.size(); i++ )
{
Object o = children.get( i );
if ( !( o instanceof Element ) )
{
continue;
}
Element child = (Element) o;
if ( namesAfter.contains( child.getName() ) )
{
webapp.addContent( i, insertAfter );
foundPoint = true;
break;
}
if ( !namesBefore.contains( child.getName() ) )
{
webapp.addContent( i + 1, insertAfter );
foundPoint = true;
break;
}
}
if ( !foundPoint )
{
webapp.addContent( insertAfter );
}
}
return webapp.indexOf( insertAfter );
}
private Document getWebXmlAsDocument( File webXml )
throws JDOMException, IOException
{
SAXBuilder builder = new SAXBuilder( false );
builder.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false );
return builder.build( webXml.toURI().toURL() );
}
}