This is an automated email from the ASF dual-hosted git repository. rfscholte pushed a commit to branch maven-xml in repository https://gitbox.apache.org/repos/asf/maven-studies.git
commit 681b08bf683592faf6c78e6a29a2a5d6853a8878 Author: rfscholte <rfscho...@apache.org> AuthorDate: Sat May 12 19:57:31 2018 +0200 Initial commit maven-xml, might end up in maven-core in the end. --- .gitignore | 4 + Jenkinsfile | 20 ++ pom.xml | 50 ++++ src/main/java/org/apache/maven/xml/SAXEvent.java | 34 +++ .../java/org/apache/maven/xml/SAXEventFactory.java | 111 ++++++++ .../java/org/apache/maven/xml/SAXEventUtils.java | 38 +++ .../maven/xml/filters/FastForwardFilter.java | 77 ++++++ .../org/apache/maven/xml/filters/ModelFilter.java | 84 ++++++ .../apache/maven/xml/filters/ParentXMLFilter.java | 283 +++++++++++++++++++++ .../xml/filters/ReactorDependencyXMLFilter.java | 124 +++++++++ .../apache/maven/xml/filters/ThisXMLFilter.java | 71 ++++++ .../java/org/apache/maven/xml/SAXUtilsTest.java | 40 +++ .../maven/xml/filters/AbstractXMLFilterTests.java | 113 ++++++++ .../apache/maven/xml/filters/ModelFilterTest.java | 121 +++++++++ .../maven/xml/filters/ParentXMLFilterTest.java | 137 ++++++++++ .../filters/ReactorDependencyXMLFilterTest.java | 80 ++++++ .../maven/xml/filters/ThisXMLFilterTest.java | 53 ++++ 17 files changed, 1440 insertions(+) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06a84e9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.classpath +/.project +/.settings diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..09ac70f --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,20 @@ +/** + * 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. + */ + +asfMavenTlpStdBuild() diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c31c650 --- /dev/null +++ b/pom.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +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. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.maven</groupId> + <artifactId>maven-parent</artifactId> + <version>31</version> + <relativePath>../pom/maven/pom.xml</relativePath> + </parent> + + <groupId>org.apache.maven</groupId> + <artifactId>maven-xml</artifactId> + <version>4.0.0-SNAPSHOT</version> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> \ No newline at end of file diff --git a/src/main/java/org/apache/maven/xml/SAXEvent.java b/src/main/java/org/apache/maven/xml/SAXEvent.java new file mode 100644 index 0000000..07da280 --- /dev/null +++ b/src/main/java/org/apache/maven/xml/SAXEvent.java @@ -0,0 +1,34 @@ +package org.apache.maven.xml; + +/* + * 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 org.xml.sax.SAXException; + +/** + * Command pattern to gather events which can be executed later on. + * + * @author Robert Scholte + * @since + */ +@FunctionalInterface +public interface SAXEvent +{ + void execute() throws SAXException; +} diff --git a/src/main/java/org/apache/maven/xml/SAXEventFactory.java b/src/main/java/org/apache/maven/xml/SAXEventFactory.java new file mode 100644 index 0000000..42739e1 --- /dev/null +++ b/src/main/java/org/apache/maven/xml/SAXEventFactory.java @@ -0,0 +1,111 @@ +package org.apache.maven.xml; + +/* + * 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 org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; + +/** + * Factory for SAXEvents + * + * @author Robert Scholte + * @since 4.0.0 + */ +public final class SAXEventFactory +{ + private final ContentHandler contentHandler; + + protected SAXEventFactory( ContentHandler contentHandler ) + { + this.contentHandler = contentHandler; + } + + public SAXEvent characters( final char[] ch, final int start, final int length ) + { + final char[] txt; + if ( start > 0 ) + { + txt = new char[length]; + System.arraycopy( ch, start, txt, 0, length ); + } + else + { + txt = ch; + } + + return () -> contentHandler.characters( txt, 0, length ); + } + + public SAXEvent endDocument() + { + return () -> contentHandler.endDocument(); + } + + public SAXEvent endElement( final String uri, final String localName, final String qName ) + { + return () -> contentHandler.endElement( uri, localName, qName ); + } + + public SAXEvent endPrefixMapping( final String prefix ) + { + return () -> contentHandler.endPrefixMapping( prefix ); + } + + public SAXEvent ignorableWhitespace( final char[] ch, final int start, final int length ) + { + return () -> contentHandler.ignorableWhitespace( ch, start, length ); + } + + public SAXEvent processingInstruction( final String target, final String data ) + { + return () -> contentHandler.processingInstruction( target, data ); + } + + public SAXEvent setDocumentLocator( final Locator locator ) + { + return () -> contentHandler.setDocumentLocator( locator ); + } + + public SAXEvent skippedEntity( final String name ) + { + return () -> contentHandler.skippedEntity( name ); + } + + public SAXEvent startDocument() + { + return () -> contentHandler.startDocument(); + } + + public SAXEvent startElement( final String uri, final String localName, final String qName, final Attributes atts ) + { + return () -> contentHandler.startElement( uri, localName, qName, atts ); + } + + public SAXEvent startPrefixMapping( final String prefix, final String uri ) + { + return () -> contentHandler.startPrefixMapping( prefix, uri ); + } + + public static SAXEventFactory newInstance( ContentHandler handler ) + { + return new SAXEventFactory( handler ); + } +} diff --git a/src/main/java/org/apache/maven/xml/SAXEventUtils.java b/src/main/java/org/apache/maven/xml/SAXEventUtils.java new file mode 100644 index 0000000..06f4f26 --- /dev/null +++ b/src/main/java/org/apache/maven/xml/SAXEventUtils.java @@ -0,0 +1,38 @@ +package org.apache.maven.xml; + +/* + * 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. + */ + +/** + * Utility class for SAXEvents + * + * @author Robert Scholte + * @since 4.0.0 + */ +public final class SAXEventUtils +{ + private SAXEventUtils() + { + } + + public static String renameQName( String oldQName, String newLocalName ) + { + return oldQName.replaceFirst( "[^:]+$", newLocalName ); + } +} diff --git a/src/main/java/org/apache/maven/xml/filters/FastForwardFilter.java b/src/main/java/org/apache/maven/xml/filters/FastForwardFilter.java new file mode 100644 index 0000000..2aba87a --- /dev/null +++ b/src/main/java/org/apache/maven/xml/filters/FastForwardFilter.java @@ -0,0 +1,77 @@ +package org.apache.maven.xml.filters; + +/* + * 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 org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.XMLFilter; +import org.xml.sax.helpers.XMLFilterImpl; + +/** + * This filter will skip all chained filter and write directly to the output + * + * @author Robert Scholte + * @since 4.0.0 + */ +public class FastForwardFilter extends XMLFilterImpl +{ + private int reports = 0; + + private ContentHandler originalHandler; + + @Override + public void startElement( String uri, String localName, String qName, Attributes atts ) + throws SAXException + { + if ( "reports".equals( localName ) ) + { + reports++; + originalHandler = getContentHandler(); + + ContentHandler outputContentHandler = getContentHandler(); + while ( outputContentHandler instanceof XMLFilter ) + { + outputContentHandler = ( (XMLFilter) outputContentHandler ).getContentHandler(); + } + setContentHandler( outputContentHandler ); + } + super.startElement( uri, localName, qName, atts ); + } + + @Override + public void endElement( String uri, String localName, String qName ) + throws SAXException + { + if ( "reports".equals( localName ) ) + { + reports--; + + if ( reports == 0 ) + { + setContentHandler( originalHandler ); + } + } + + super.endElement( uri, localName, qName ); + } + + +} diff --git a/src/main/java/org/apache/maven/xml/filters/ModelFilter.java b/src/main/java/org/apache/maven/xml/filters/ModelFilter.java new file mode 100644 index 0000000..82ed7d0 --- /dev/null +++ b/src/main/java/org/apache/maven/xml/filters/ModelFilter.java @@ -0,0 +1,84 @@ +package org.apache.maven.xml.filters; + +/* + * 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 org.xml.sax.SAXException; +import org.xml.sax.XMLFilter; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLFilterImpl; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * + * @author Robert Scholte + * @since 4.0.0 + * + */ +public class ModelFilter + extends XMLFilterImpl +{ + private final XMLFilterChainBuilder builder; + + public ModelFilter() throws SAXException + { + this( XMLReaderFactory.createXMLReader() ); + } + + public ModelFilter( XMLReader parent ) + { + builder = new XMLFilterChainBuilder( parent ); + + setParent( builder.build() ); + + addFilter( new FastForwardFilter() ); + } + + public ModelFilter addFilter( XMLFilter filter ) + { + builder.addFilter( filter ); + + setParent( builder.build() ); + + return this; + } + + + private static class XMLFilterChainBuilder + { + private XMLReader parent; + + XMLFilterChainBuilder( XMLReader parent ) + { + this.parent = parent; + } + + XMLFilterChainBuilder addFilter( XMLFilter filter ) + { + filter.setParent( parent ); + parent = filter; + return this; + } + + XMLReader build() + { + return parent; + } + } +} diff --git a/src/main/java/org/apache/maven/xml/filters/ParentXMLFilter.java b/src/main/java/org/apache/maven/xml/filters/ParentXMLFilter.java new file mode 100644 index 0000000..67bee88 --- /dev/null +++ b/src/main/java/org/apache/maven/xml/filters/ParentXMLFilter.java @@ -0,0 +1,283 @@ +package org.apache.maven.xml.filters; + +/* + * 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.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import org.apache.maven.xml.SAXEvent; +import org.apache.maven.xml.SAXEventFactory; +import org.apache.maven.xml.SAXEventUtils; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.XMLFilterImpl; + +/** + * <p> + * Transforms relativePath to version. + * </p> + * + * @author Robert Scholte + */ +public class ParentXMLFilter + extends XMLFilterImpl +{ + private boolean parsingParent = false; + + // states + private static final int OTHER = 0; + + private static final int RELATIVEPATH = 1; + + private int state; + + /** + * If parent has no version-element, rewrite relativePath to version.<br> + * If parent has version-element, then remove relativePath.<br> + * Order of elements must stay the same. + */ + private boolean hasVersion; + + private String resolvedVersion; + + private List<SAXEvent> saxEvents = new ArrayList<>(); + + private SAXEventFactory eventFactory; + + private final Function<String, String> relativePathMapper; + + public ParentXMLFilter( Function<String, String> relativePathMapper ) + { + this.relativePathMapper = relativePathMapper; + } + + private SAXEventFactory getEventFactory() + { + if ( eventFactory == null ) + { + eventFactory = SAXEventFactory.newInstance( getContentHandler() ); + } + return eventFactory; + } + + private void processEvent( final SAXEvent event ) + throws SAXException + { + if ( parsingParent ) + { + final int eventState = state; + + saxEvents.add( () -> + { + if ( !( eventState == RELATIVEPATH && hasVersion ) ) + { + event.execute(); + } + } ); + } + else + { + event.execute(); + } + } + + @Override + public void startElement( String uri, String localName, String qName, Attributes atts ) + throws SAXException + { + if ( !parsingParent && "parent".equals( localName ) ) + { + parsingParent = true; + } + + if ( parsingParent ) + { + if ( "relativePath".equals( localName ) ) + { + state = RELATIVEPATH; + processEvent( () -> + { + if ( resolvedVersion != null ) + { + String versionQName = SAXEventUtils.renameQName( qName, "version" ); + + getEventFactory().startElement( uri, "version", versionQName, null ).execute(); + } + else + { + getEventFactory().startElement( uri, localName, qName, atts ).execute(); + } + } ); + return; + } + else + { + state = OTHER; + } + + if ( "version".equals( localName ) ) + { + hasVersion = true; + } + processEvent( getEventFactory().startElement( uri, localName, qName, atts ) ); + } + else + { + super.startElement( uri, localName, qName, atts ); + } + } + + @Override + public void characters( char[] ch, int start, int length ) + throws SAXException + { + if ( parsingParent && state == RELATIVEPATH ) + { + String relativePath = new String( ch, start, length ); + resolvedVersion = relativePathToVersion( relativePath ); + + processEvent( () -> + { + if ( resolvedVersion != null ) + { + getEventFactory().characters( resolvedVersion.toCharArray(), 0, + resolvedVersion.length() ).execute(); + } + else + { + getEventFactory().characters( ch, start, length ).execute(); + } + } ); + } + else + { + processEvent( getEventFactory().characters( ch, start, length ) ); + } + + } + + @Override + public void endDocument() + throws SAXException + { + processEvent( getEventFactory().endDocument() ); + } + + @Override + public void endElement( String uri, String localName, String qName ) + throws SAXException + { + if ( !parsingParent ) + { + super.endElement( uri, localName, qName ); + } + else if ( "relativePath".equals( localName ) ) + { + processEvent( () -> + { + if ( resolvedVersion != null ) + { + String versionQName = SAXEventUtils.renameQName( qName, "version" ); + getEventFactory().endElement( uri, "version", versionQName ).execute(); + } + else + { + getEventFactory().endElement( uri, localName, qName ).execute(); + } + } ); + } + else + { + if ( "parent".equals( localName ) ) + { + // not with streams due to checked SAXException + for ( SAXEvent saxEvent : saxEvents ) + { + saxEvent.execute(); + } + parsingParent = false; + } + processEvent( getEventFactory().endElement( uri, localName, qName ) ); + } + } + + @Override + public void endPrefixMapping( String prefix ) + throws SAXException + { + processEvent( getEventFactory().endPrefixMapping( prefix ) ); + } + + @Override + public void ignorableWhitespace( char[] ch, int start, int length ) + throws SAXException + { + processEvent( getEventFactory().ignorableWhitespace( ch, start, length ) ); + } + + @Override + public void processingInstruction( String target, String data ) + throws SAXException + { + processEvent( getEventFactory().processingInstruction( target, data ) ); + + } + + @Override + public void setDocumentLocator( Locator locator ) + { + try + { + processEvent( getEventFactory().setDocumentLocator( locator ) ); + } + catch ( SAXException e ) + { + // noop + } + } + + @Override + public void skippedEntity( String name ) + throws SAXException + { + processEvent( getEventFactory().skippedEntity( name ) ); + } + + @Override + public void startDocument() + throws SAXException + { + processEvent( getEventFactory().startDocument() ); + } + + @Override + public void startPrefixMapping( String prefix, String uri ) + throws SAXException + { + processEvent( getEventFactory().startPrefixMapping( prefix, uri ) ); + } + + protected String relativePathToVersion( String relativePath ) + { + return relativePathMapper.apply( relativePath ); + } +} diff --git a/src/main/java/org/apache/maven/xml/filters/ReactorDependencyXMLFilter.java b/src/main/java/org/apache/maven/xml/filters/ReactorDependencyXMLFilter.java new file mode 100644 index 0000000..cf14fd7 --- /dev/null +++ b/src/main/java/org/apache/maven/xml/filters/ReactorDependencyXMLFilter.java @@ -0,0 +1,124 @@ +package org.apache.maven.xml.filters; + +/* + * 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.util.function.Function; + +import org.apache.maven.xml.SAXEventUtils; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.XMLFilterImpl; + +/** + * Will apply the version if the dependency is part of the reactor + * + * @author Robert Scholte + * @since 4.0.0 + */ +public class ReactorDependencyXMLFilter extends XMLFilterImpl +{ + + // states + private static final int GROUPID = 1; + + private static final int ARTIFACTID = 2; + + private static final int OTHER = 0; + + private int state; + + private boolean hasVersion; + + private String groupId; + + private String artifactId; + + private final Function<String, String> reactorVersionMapper; + + public ReactorDependencyXMLFilter( Function<String, String> reactorVersionMapper ) + { + this.reactorVersionMapper = reactorVersionMapper; + } + + @Override + public void startElement( String uri, String localName, String qName, Attributes atts ) + throws SAXException + { + if ( "groupId".equals( localName ) ) + { + state = GROUPID; + } + else if ( "artifactId".equals( localName ) ) + { + state = ARTIFACTID; + } + else + { + state = OTHER; + } + + if ( "version".equals( localName ) ) + { + hasVersion = true; + } + super.startElement( uri, localName, qName, atts ); + } + + @Override + public void characters( char[] ch, int start, int length ) + throws SAXException + { + if ( state == GROUPID ) + { + groupId = new String( ch, start, length ); + } + else if ( state == ARTIFACTID ) + { + artifactId = new String( ch, start, length ); + } + super.characters( ch, start, length ); + } + + @Override + public void endElement( String uri, String localName, String qName ) + throws SAXException + { + if ( "dependency".equals( localName ) && !hasVersion ) + { + String version = getVersion(); + + // dependency is not part of reactor, probably it is managed + if ( version != null ) + { + String versionQName = SAXEventUtils.renameQName( qName, "version" ); + super.startElement( uri, "version", versionQName, null ); + super.characters( version.toCharArray(), 0, version.length() ); + super.endElement( uri, "version", versionQName ); + } + } + super.endElement( uri, localName, qName ); + } + + private String getVersion() + { + return reactorVersionMapper.apply( groupId + ':' + artifactId ); + } + +} diff --git a/src/main/java/org/apache/maven/xml/filters/ThisXMLFilter.java b/src/main/java/org/apache/maven/xml/filters/ThisXMLFilter.java new file mode 100644 index 0000000..48d3dde --- /dev/null +++ b/src/main/java/org/apache/maven/xml/filters/ThisXMLFilter.java @@ -0,0 +1,71 @@ +package org.apache.maven.xml.filters; + +/* + * 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.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.XMLFilterImpl; + +/** + * Resolves all ${this.*} occurrences + * + * @author Robert Scholte + * + */ +public class ThisXMLFilter + extends XMLFilterImpl +{ + static final Pattern THIS_PATTERN = Pattern.compile( "\\$\\{this\\..+}" ); + + private final Function<String, String> resolver; + + public ThisXMLFilter( Function<String, String> resolver ) + { + this.resolver = resolver; + } + + @Override + public void characters( char[] ch, int start, int length ) + throws SAXException + { + String text = new String( ch, start, length ); + + // assuming this has the best performance + if ( text.contains( "${this." ) ) + { + Matcher m = THIS_PATTERN.matcher( text ); + StringBuffer sb = new StringBuffer(); + while ( m.find() ) + { + m.appendReplacement( sb, resolver.apply( m.group() ) ); + } + m.appendTail( sb ); + String newText = sb.toString(); + super.characters( newText.toCharArray(), 0, newText.length() ); + } + else + { + super.characters( ch, start, length ); + } + } +} diff --git a/src/test/java/org/apache/maven/xml/SAXUtilsTest.java b/src/test/java/org/apache/maven/xml/SAXUtilsTest.java new file mode 100644 index 0000000..a720c7f --- /dev/null +++ b/src/test/java/org/apache/maven/xml/SAXUtilsTest.java @@ -0,0 +1,40 @@ +package org.apache.maven.xml; + +/* + * 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 static org.junit.Assert.*; + +import org.junit.Test; + +public class SAXUtilsTest +{ + @Test + public void testWithNamespace() + { + assertEquals( "namespace:b", SAXEventUtils.renameQName( "namespace:a", "b" )); + } + + @Test + public void testWithoutNamespace() + { + assertEquals( "b", SAXEventUtils.renameQName( "a", "b" )); + } + +} diff --git a/src/test/java/org/apache/maven/xml/filters/AbstractXMLFilterTests.java b/src/test/java/org/apache/maven/xml/filters/AbstractXMLFilterTests.java new file mode 100644 index 0000000..d19ec99 --- /dev/null +++ b/src/test/java/org/apache/maven/xml/filters/AbstractXMLFilterTests.java @@ -0,0 +1,113 @@ +package org.apache.maven.xml.filters; + +/* + * 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.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLFilter; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLFilterImpl; +import org.xml.sax.helpers.XMLReaderFactory; + +public class AbstractXMLFilterTests +{ + + public AbstractXMLFilterTests() + { + super(); + } + + protected String transform( String input, XMLFilter filter ) + throws TransformerException, SAXException + { + XMLReader reader = XMLReaderFactory.createXMLReader(); + + XMLFilter parent = filter; + while ( parent.getParent() instanceof XMLFilter ) + { + parent = (XMLFilter) parent.getParent(); + } + parent.setParent( reader ); + + Writer writer = new StringWriter(); + StreamResult result = new StreamResult( writer ); + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" ); + + SAXSource transformSource = new SAXSource( filter, new InputSource( new StringReader( input ) ) ); + + transformer.transform( transformSource, result ); + + return writer.toString(); + } + + protected static final class CharactersXMLFilter + extends XMLFilterImpl + { + @Override + public void characters( char[] ch, int start, int length ) + throws SAXException + { + super.characters( new char[] { '*', '*', '*' }, 0, 3 ); + } + } + + protected static final class ElementXMLFilter + extends XMLFilterImpl + { + public ElementXMLFilter() + { + super(); + } + + public ElementXMLFilter( XMLReader parent ) + { + super( parent ); + } + + @Override + public void startElement( String uri, String localName, String qName, Attributes atts ) + throws SAXException + { + super.startElement( uri, "elm", "elm", atts ); + } + + @Override + public void endElement( String uri, String localName, String qName ) + throws SAXException + { + super.endElement( uri, "elm", "elm" ); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/apache/maven/xml/filters/ModelFilterTest.java b/src/test/java/org/apache/maven/xml/filters/ModelFilterTest.java new file mode 100644 index 0000000..390a9bc --- /dev/null +++ b/src/test/java/org/apache/maven/xml/filters/ModelFilterTest.java @@ -0,0 +1,121 @@ +package org.apache.maven.xml.filters; + +/* + * 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 static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +/** + * + * @author Robert Scholte + * @since 4.0.0 + */ +public class ModelFilterTest extends AbstractXMLFilterTests +{ + private ModelFilter filter; + + @Before + public void setUp() throws Exception + { + filter = new ModelFilter(); + + filter.addFilter( new ParentXMLFilter( x -> "1.0.0" ) ); + filter.addFilter( new ThisXMLFilter( x -> "1.0.0" ) ); + filter.addFilter( new ReactorDependencyXMLFilter( x -> "2.0.0" ) ); + } + + @Test + public void testParentNoRelativePath() throws Exception + { + + String input = "<project><parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>VERSION</version>" + + "</parent></project>"; + String expected = input; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testThisVersion() throws Exception + { + String input = "<project><parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>${this.version}</version>" + + "</parent></project>"; + + String expected = "<project><parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>1.0.0</version>" + + "</parent></project>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testNoVersion() throws Exception + { + String input = "<project><parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<relativePath>RELATIVEPATH</relativePath>" + + "</parent></project>"; + + String expected = "<project><parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>1.0.0</version>" + + "</parent></project>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + // reports are deprecated and should not be resolved + @Test + public void testReports() throws Exception + { + String input = "<project><reports><parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<relativePath>RELATIVEPATH</relativePath>" + + "</parent>" + + "<name>Project ${this.version}</name>" + + "</reports></project>"; + + String expected = input; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + +} diff --git a/src/test/java/org/apache/maven/xml/filters/ParentXMLFilterTest.java b/src/test/java/org/apache/maven/xml/filters/ParentXMLFilterTest.java new file mode 100644 index 0000000..487c350 --- /dev/null +++ b/src/test/java/org/apache/maven/xml/filters/ParentXMLFilterTest.java @@ -0,0 +1,137 @@ +package org.apache.maven.xml.filters; + +/* + * 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 static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.XMLFilter; + +public class ParentXMLFilterTest extends AbstractXMLFilterTests +{ + private ParentXMLFilter filter; + + @Before + public void setUp() + { + filter = new ParentXMLFilter( r -> "1.0.0" ); + } + + @Test + public void testMinimum() throws Exception + { + String input = "<parent/>"; + String expected = input; + String actual = transform( input, filter ); + assertEquals( expected, actual ); + } + + @Test + public void testNoRelativePath() throws Exception + { + String input = "<parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>VERSION</version>" + + "</parent>"; + String expected = input; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testNoVersion() throws Exception + { + String input = "<parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<relativePath>RELATIVEPATH</relativePath>" + + "</parent>"; + String expected = "<parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>1.0.0</version>" + + "</parent>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testInvalidRelativePath() throws Exception + { + XMLFilter filter = new ParentXMLFilter( r -> null ); + + String input = "<parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<relativePath>RELATIVEPATH</relativePath>" + + "</parent>"; + String expected = input; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testRelativePathAndVersion() throws Exception + { + String input = "<parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<relativePath>RELATIVEPATH</relativePath>" + + "<version>1.0.0</version>" + + "</parent>"; + String expected = "<parent>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>1.0.0</version>" + + "</parent>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testWithWeirdNamespace() throws Exception + { + String input = "<relativePath:parent xmlns:relativePath=\"relativePath\">" + + "<relativePath:groupId>GROUPID</relativePath:groupId>" + + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>" + + "<relativePath:relativePath>RELATIVEPATH</relativePath:relativePath>" + + "<relativePath:version>1.0.0</relativePath:version>" + + "</relativePath:parent>"; + String expected = "<relativePath:parent xmlns:relativePath=\"relativePath\">" + + "<relativePath:groupId>GROUPID</relativePath:groupId>" + + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>" + + "<relativePath:version>1.0.0</relativePath:version>" + + "</relativePath:parent>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } +} diff --git a/src/test/java/org/apache/maven/xml/filters/ReactorDependencyXMLFilterTest.java b/src/test/java/org/apache/maven/xml/filters/ReactorDependencyXMLFilterTest.java new file mode 100644 index 0000000..fe95e60 --- /dev/null +++ b/src/test/java/org/apache/maven/xml/filters/ReactorDependencyXMLFilterTest.java @@ -0,0 +1,80 @@ +package org.apache.maven.xml.filters; + +/* + * 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 static org.junit.Assert.*; + +import org.junit.Test; +import org.xml.sax.XMLFilter; + +public class ReactorDependencyXMLFilterTest extends AbstractXMLFilterTests +{ + private final XMLFilter filter = new ReactorDependencyXMLFilter( r -> "1.0.0" ); + + @Test + public void testDefaultDependency() throws Exception + { + String input = "<dependency>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>VERSION</version>" + + "</dependency>"; + String expected = input; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testManagedDependency() throws Exception + { + XMLFilter filter = new ReactorDependencyXMLFilter( r -> null ); + + String input = "<dependency>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "</dependency>"; + String expected = input; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testReactorDependency() throws Exception + { + String input = "<dependency>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "</dependency>"; + String expected = "<dependency>" + + "<groupId>GROUPID</groupId>" + + "<artifactId>ARTIFACTID</artifactId>" + + "<version>1.0.0</version>" + + "</dependency>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + +} diff --git a/src/test/java/org/apache/maven/xml/filters/ThisXMLFilterTest.java b/src/test/java/org/apache/maven/xml/filters/ThisXMLFilterTest.java new file mode 100644 index 0000000..7c9aeda --- /dev/null +++ b/src/test/java/org/apache/maven/xml/filters/ThisXMLFilterTest.java @@ -0,0 +1,53 @@ +package org.apache.maven.xml.filters; + +/* + * 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 static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.xml.sax.XMLFilter; + +public class ThisXMLFilterTest extends AbstractXMLFilterTests +{ + private XMLFilter filter = new ThisXMLFilter( t-> "THIS" ); + + @Test + public void testReplaceAll() throws Exception + { + String input = "<project><name>${this.version}</name></project>"; + String expected = "<project><name>THIS</name></project>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + + @Test + public void testReplaceSegment() throws Exception + { + String input = "<project><name>Project ${this.version}</name></project>"; + String expected = "<project><name>Project THIS</name></project>"; + + String actual = transform( input, filter ); + + assertEquals( expected, actual ); + } + +} -- To stop receiving notification emails like this one, please contact rfscho...@apache.org.