Subversion Repositories XServices

Compare Revisions

No changes between revisions

Ignore whitespace Rev 148 → Rev 149

/SVN-ALFEventEmitter/trunk/.classpath
0,0 → 1,7
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=SVNConnector&amp;ivyXmlPath=ivy.xml&amp;confs=*"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/.project
0,0 → 1,18
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SVN-ALFEventEmitter</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.apache.ivyde.eclipse.ivynature</nature>
</natures>
</projectDescription>
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/ivy.xml
0,0 → 1,44
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- 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. -->
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
<info organisation="Brutex Network" module="SVN-ALFEventEmitter" status="integration">
</info>
 
<configurations>
<conf name="default" visibility="public" description="runtime dependencies and master artifact can be used with this conf" extends="runtime,master"/>
<conf name="master" visibility="public" description="contains only the artifact published by this module itself, with no transitive dependencies"/>
<conf name="compile" visibility="public" description="this is the default scope, used if none is specified. Compile dependencies are available in all classpaths." extends="master"/>
<conf name="provided" visibility="public" description="this is much like compile, but indicates you expect the JDK or a container to provide it. It is only available on the compilation classpath, and is not transitive."/>
<conf name="runtime" visibility="public" description="this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath." extends="compile"/>
<conf name="test" visibility="private" description="this scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases." extends="runtime"/>
<conf name="system" visibility="public" description="this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository."/>
<conf name="sources" visibility="public" description="this configuration contains the source artifact of this module, if any."/>
<conf name="javadoc" visibility="public" description="this configuration contains the javadoc artifact of this module, if any."/>
<conf name="optional" visibility="public" description="contains all optional dependencies"/>
</configurations>
 
<dependencies defaultconf="*->#(master),master(*)">
 
<dependency org="log4j" name="log4j" rev="1.2.17"/>
<dependency org="commons-configuration" name="commons-configuration" rev="1.10"/>
<dependency org="commons-cli" name="commons-cli" rev="1.2"/>
<dependency org="org.apache.httpcomponents" name="httpclient" rev="4.3.1"/>
 
<dependency org="org.apache.ws.commons.axiom" name="axiom-api" rev="1.2.14"/>
<dependency org="org.apache.ws.commons.axiom" name="axiom-impl" rev="1.2.14"/>
</dependencies>
</ivy-module>
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/src/LICENSE.txt
0,0 → 1,13
Copyright 2013 Brian Rosenberger (Brutex Network)
 
Licensed 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.
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/src/net/brutex/svn/SVNLookCommand.java
0,0 → 1,42
/*
* Copyright 2013 Brian Rosenberger (Brutex Network)
*
* Licensed 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.
*/
package net.brutex.svn;
 
/**
* The Enum SVNLookCommand. Lists supported svnlook commands
*
* @author Brian Rosenberger, bru(at)brutex.de
* @since 0.1
*/
public enum SVNLookCommand {
 
CHANGED("changed"),
LOG("log"),
AUTHOR("author");
private final String value;
private SVNLookCommand(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
 
}
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/src/net/brutex/svn/SVNLookExecutor.java
0,0 → 1,177
/*
* Copyright 2013 Brian Rosenberger (Brutex Network)
*
* Licensed 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.
*/
package net.brutex.svn;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
 
import net.brutex.svn.SVNCommitInfo.ChangeType;
 
import org.apache.log4j.Logger;
 
/** Executes the svnlook utility
*
* @author Brian Rosenberger bru(at)brutex.de
* @since 0.1
 
*/
public class SVNLookExecutor {
private Logger logger = Logger.getLogger(SVNLookExecutor.class);
private final File svnlook;
private final String repos;
private String TXN = null;
private String rev = null;
/**
* Instantiates a new sVN look executor.
*
* @param svnlook the svnlook
* @param repos the repos
*/
public SVNLookExecutor(File svnlook, String repos) {
if(! svnlook.exists() ) throw new IllegalArgumentException( String.format("The svnlook executable at '%s' does not exist.", svnlook.toString()));
if(! svnlook.isFile() ) throw new IllegalArgumentException( String.format("The svnlook utility at'%s' is not a file.", svnlook.toString()));
logger.debug(String.format("Instantiating '%s' with svnlook at '%s'.", this.getClass().getCanonicalName(), svnlook.toString()));
this.svnlook = svnlook;
logger.debug(String.format("Working against svn repository at '%s'.", repos));
this.repos = repos;
}
 
/**
* Execute svn look.
*
* @param command the command
* @return the string
*/
private String executeSVNLook(SVNLookCommand command) {
StringBuilder sb = new StringBuilder();
StringBuilder sberr = new StringBuilder();
//This throws an IllegalArgumentException when neither TXN nor REV is valid
String[] params;
try {
params = getTargetParam();
} catch (IllegalArgumentException e) {
logger.error(e.getMessage());
throw e;
}
try {
List<String> cmdline = new ArrayList<String>(5);
cmdline.add(svnlook.toString());
cmdline.add(command.getValue());
cmdline.add(params[0]);
cmdline.add(params[1]);
cmdline.add(repos);
 
ProcessBuilder pf = new ProcessBuilder(cmdline);
logger.debug(String.format("Executing svnlook with commandline '%s'.", pf.command()));
Process svnprocess = pf.start();
BufferedReader stdin = new BufferedReader(new InputStreamReader(svnprocess.getInputStream()));
BufferedReader stderr = new BufferedReader(new InputStreamReader(svnprocess.getErrorStream()));
String s;
while( (s = stdin.readLine()) != null ) {
sb.append(s + '\n');
}
while( (s = stderr.readLine()) != null ) {
sberr.append(s + '\n');
}
stdin.close(); stderr.close();
} catch (IOException e) {
logger.error( String.format( "Error calling the svnlook utility: '%s'", e.getMessage()));
e.printStackTrace();
}
String error = sberr.toString();
if( error.length()>0 ) {
error = "Failed to call svnlook. The STDERR was '"+error+"'";
logger.error(error);
throw new IllegalArgumentException(error);
}
String output = sb.toString().trim();
logger.debug(String.format("Svnlook output was '%s'", output));
return output;
}
/*
* Returns either -t TXN oder -rev REVISION
*
* @returns
*/
private String[] getTargetParam() {
String[] result = new String[2];
if( (TXN==null || TXN.length()<=0) && (rev==null || rev.length()<=0) ) throw new IllegalArgumentException("Either TXN or revision must be provided.");
if( TXN!=null && TXN.length()>0 && rev!=null && rev.length()>0 ) throw new IllegalArgumentException("Both, TXN and revision are given. Don't know what to use.");
if( TXN!=null && TXN.length()>0) {
result[0] = "-t";
result[1] = TXN;
return result;
}
if( rev!=null && rev.length()>0) {
result[0] = "-r";
result[1] = rev;
return result;
}
throw new IllegalArgumentException("Either TXN or revision must be provided.");
}
public void setTXN(String TXN) {
if(TXN==null || TXN.length()<=0) throw new IllegalArgumentException("TXN cannot be null or empty.");
this.TXN = TXN;
}
public void setRev(String rev) {
if(rev==null || rev.length()<=0) throw new IllegalArgumentException("Revision cannot be null or empty.");
this.rev = rev;
}
public SVNCommitInfo getCommitInfo() {
String author = executeSVNLook(SVNLookCommand.AUTHOR);
String logmessage = executeSVNLook(SVNLookCommand.LOG);
String files = executeSVNLook(SVNLookCommand.CHANGED);
SVNCommitInfo result = new SVNCommitInfo(author,
new Date(),
logmessage);
files += "\n";
StringTokenizer tokenizer = new StringTokenizer(files, "\n");
String s;
while( tokenizer.hasMoreTokens()) {
s=tokenizer.nextToken();
logger.debug(String.format("Tokenizing file list. Token '%s'.", s));
if(s.startsWith("A")) { result.addFileInfo(ChangeType.ADDED, s.substring(1).trim()); continue; }
if(s.startsWith("D")) { result.addFileInfo(ChangeType.DELETED, s.substring(1).trim()); continue; }
if(s.startsWith("UU")) { result.addFileInfo(ChangeType.BOTHUPDATE, s.substring(2).trim()); continue; }
if(s.startsWith("_U")) { result.addFileInfo(ChangeType.METAUPDATE, s.substring(2).trim()); continue; }
if(s.startsWith("U")) { result.addFileInfo(ChangeType.UPDATED, s.substring(1).trim()); continue; }
}
result.setTxn(TXN);
result.setRev(rev);
return result;
}
 
}
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/src/net/brutex/svn/SVNCommitInfo.java
0,0 → 1,355
/*
* Copyright 2013 Brian Rosenberger (Brutex Network)
*
* Licensed 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.
*/
package net.brutex.svn;
 
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import org.apache.log4j.Logger;
 
/**
* The Class SVNCommitInfo represents changes commited to
* a svn repository. The information is based on svnlook.
*
* 'A ' Object dem Projektarchiv hinzugefügt
* 'D ' Objekt aus dem Projektarchiv gelöscht
* 'U ' Dateiinhalt geändert
* '_U' Eigenschaften eines Objektes geändert
* 'UU' Dateiinhalt und Eigenschaften geändert
*
* @author Brian Rosenberger, bru(at)brutex.de
* @since 0.1
*
*/
public class SVNCommitInfo {
/** The logger. */
private final Logger logger = Logger.getLogger(SVNCommitInfo.class);
/** The author. */
private final String author;
/** The commit message */
private final String logmessage;
/** The date. */
private final Date date;
/** The Alist. */
private final List<String> Alist = new ArrayList<String>(0);
/** The Dlist. */
private final List<String> Dlist = new ArrayList<String>(0);
/** The Ulist. */
private final List<String> Ulist = new ArrayList<String>(5);
/** The _ ulist. */
private final List<String> _Ulist = new ArrayList<String>(0);
/** The U ulist. */
private final List<String> UUlist = new ArrayList<String>(0);
/** The issues. */
private final List<String> issues = new ArrayList<String>(1);
/** The txn. */
private String txn="";
/** The rev. */
private String rev="";
/**
* Instantiates a new SVN commit info.
*
* @param author the commiter
* @param date the commit date
* @param logmessage the commit message
*/
public SVNCommitInfo(String author, Date date, String logmessage) {
this.author = author;
this.date = date;
this.logmessage = logmessage;
}
/**
* Adds the file info.
*
* @param t the t
* @param file the file
*/
public void addFileInfo(ChangeType t, String file) {
switch (t) {
case ADDED:
Alist.add(file);
break;
case DELETED:
Dlist.add(file);
break;
case UPDATED:
Ulist.add(file);
break;
case METAUPDATE:
_Ulist.add(file);
break;
case BOTHUPDATE:
UUlist.add(file);
break;
 
default:
break;
}
}
/**
* Gets the author.
*
* @return the author
*/
public String getAuthor() {
return author;
}
/**
* Gets the commit message.
*
* @return the commit message
*/
public String getLogmessage() {
return logmessage;
}
/**
* Gets the commit date.
*
* @return the commit date
*/
public Date getDate() {
return date;
}
/**
* Gets the svn transaction id.
*
* @return the txn
*/
public String getTxn() {
return txn;
}
/**
* Sets the txn.
*
* @param txn the new txn
*/
public void setTxn(String txn) {
this.txn = txn;
}
/**
* Gets the id. This is either the txn or revision.
*
* @return the id
*/
public String getId() {
if(txn!=null) return txn;
return rev;
}
/**
* Sets the rev.
*
* @param rev the new rev
*/
public void setRev(String rev) {
this.rev = rev;
}
/**
* Gets the rev.
*
* @return the rev
*/
public String getRev() {
return rev;
}
/*
* http://openbook.galileocomputing.de/javainsel9/javainsel_04_007.htm#mjd5b5d84cb3f1b5bcb7638ea9221a491f
*/
/**
* Parses the issues.
*
* @param patterns the patterns
*/
public void parseIssues(String[] patterns) {
issues.clear(); //reset
int count = 0;
for(String p : patterns) {
Pattern regex = Pattern.compile(p);
Matcher matcher = regex.matcher(logmessage);
logger.debug(String.format("Matching regex pattern '%s' against logmessage '%s'.", matcher.pattern().pattern(), logmessage));
while( matcher.find()) {
issues.add( matcher.group() );
logger.debug("Found issue '" + matcher.group() + "' in the logmessage.");
count++;
}
}
logger.debug("Found '" + count + "' issues in the logmessage.");
}
/**
* Gets the change file list as string.
*
* @return the change file list as string
*/
public String getChangeFileListAsString() {
StringBuilder sb = new StringBuilder();
for (Iterator<String> iterator = Alist.iterator(); iterator.hasNext();)
{
sb.append("A \t");
sb.append(iterator.next());
sb.append("\n");
}
for (Iterator<String> iterator = Dlist.iterator(); iterator.hasNext();)
{
sb.append("D \t");
sb.append(iterator.next());
sb.append("\n");
}
for (Iterator<String> iterator = Ulist.iterator(); iterator.hasNext();)
{
sb.append("U \t");
sb.append(iterator.next());
sb.append("\n");
}
for (Iterator<String> iterator = _Ulist.iterator(); iterator.hasNext();)
{
sb.append("_U\t");
sb.append(iterator.next());
sb.append("\n");
}
for (Iterator<String> iterator = UUlist.iterator(); iterator.hasNext();)
{
sb.append("UU\t");
sb.append(iterator.next());
sb.append("\n");
}
sb.append("Summary: " + (Ulist.size()+UUlist.size()+_Ulist.size()) + " files updated, ");
sb.append(Alist.size() + " files added, " + Dlist.size() + " files deleted.");
return sb.toString();
}
/**
* Gets the added files.
*
* @return the added files
*/
public List<String> getAddedFiles() {
return Alist;
}
/**
* Gets the deleted files.
*
* @return the deleted files
*/
public List<String> getDeletedFiles() {
return Dlist;
}
/**
* Gets the changed files.
*
* @return the changed files
*/
public List<String> getChangedFiles() {
List<String> changed = new ArrayList<String>();
changed.addAll(Ulist);
changed.addAll(UUlist);
changed.addAll(_Ulist);
return changed;
}
/**
* Gets the issues.
*
* @return the issues
*/
public List<String> getIssues() {
return issues;
}
/**
* The Enum ChangeType.
*
* @author Brian Rosenberger, bru(at)brutex.de
*/
public enum ChangeType {
/** The added. */
ADDED("A "),
/** The deleted. */
DELETED("D "),
/** The updated. */
UPDATED("U "),
/** The metaupdate. */
METAUPDATE("_U"),
/** The bothupdate. */
BOTHUPDATE("UU");
/** The indicator. */
private final String indicator;
/**
* Instantiates a new change type.
*
* @param svn the svn
*/
private ChangeType(String svn) {
this.indicator = svn;
}
/**
* Gets the enum.
*
* @param s the s
* @return the enum
*/
public static ChangeType getEnum(String s) {
for(ChangeType e : ChangeType.values()) {
if(s.equals(e.getIndicator())) return e;
}
throw new IllegalArgumentException("ChangeType enum for value '"+s+"' does not exist.");
}
/**
* Gets the indicator.
*
* @return the indicator
*/
public String getIndicator() {
return this.indicator;
}
}
 
}
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/src/net/brutex/emitter/SimpleHttpEvent.java
0,0 → 1,100
/*
* Copyright 2013 Brian Rosenberger (Brutex Network)
*
* Licensed 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.
*/
package net.brutex.emitter;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
 
/**
* Construct a HTTP POST and send it.
*
* @author Brian Rosenberger, bru(at)brutex.de
* @since 0.1
*/
public class SimpleHttpEvent {
private final Logger logger = Logger.getLogger(SimpleHttpEvent.class);
private final String url;
private final String soapBody;
private long duration = 0;
/**
* Instantiates a new simple http event.
*
* @param url the url
* @param soapBody the soap body
*/
public SimpleHttpEvent(String url, String soapBody) {
this.url = url;
this.soapBody = soapBody;
}
/**
* Send soap.
*
* @param url the url
* @param soapBody the soap body
* @throws ClientProtocolException the client protocol exception
* @throws IOException Signals that an I/O exception has occurred.
*/
public void sendSoap(boolean isDropResponse) throws ClientProtocolException, IOException {
long start = System.currentTimeMillis();
HttpPost post = new HttpPost(url);
post.addHeader("Accept" , "text/xml");
post.addHeader("SOAPAction","");
EntityBuilder entitybuilder = EntityBuilder.create();
entitybuilder.setContentEncoding("UTF-8");
entitybuilder.setText(soapBody);
HttpEntity entity = entitybuilder.build();
post.setEntity(entity);
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpResponse r = httpclient.execute(post);
if(! isDropResponse) {
HttpEntity e = r.getEntity();
StringBuilder sb = new StringBuilder();
BufferedReader in = new BufferedReader(new InputStreamReader(e.getContent()));
String s;
while( (s=in.readLine()) != null) {
sb.append(s);
}
logger.debug("Response: \n " + sb.toString());
} else {
logger.debug("Response was dropped.");
}
duration = System.currentTimeMillis() - start;
}
/**
* Get the response time of the soap call in milliseconds.
*
* @return duration or '0' if not yet executed
*/
public long getDuration() {
return duration;
}
}
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/src/net/brutex/emitter/ALFEmitter.java
0,0 → 1,431
/*
* Copyright 2013 Brian Rosenberger (Brutex Network)
*
* Licensed 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.
*/
package net.brutex.emitter;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
 
import javax.xml.stream.XMLStreamException;
 
import net.brutex.svn.SVNCommitInfo;
import net.brutex.svn.SVNLookExecutor;
 
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMComment;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.OMXMLBuilderFactory;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.ParseException;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.http.client.ClientProtocolException;
import org.apache.log4j.Logger;
import org.jaxen.JaxenException;
 
 
/**
* The Class ALFEmitter.
*
* @author Brian Rosenberger, bru(at)brutex.de
* @since 0.1
*/
public class ALFEmitter {
private static final String version = "0.1";
static Logger logger = Logger.getRootLogger();
private static final String PARAM_REPOS = "repos";
private static final String PARAM_TXN = "txn";
private static final String PARAM_REV = "rev";
private static final String PARAM_CONFIG = "conf";
 
/**
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
CommandLineParser parser = new BasicParser();
CommandLine cmd = null;;
try {
cmd = parser.parse( getOptions(), args);
} catch (ParseException e1) {
logger.error(e1.getMessage());
printHelp();
System.exit(1);
}
ALFEmitter emitter = new ALFEmitter(cmd, startTime);
long endTime = System.currentTimeMillis();
logger.debug("Total execution took '"+(endTime-startTime)+"' milliseconds.");
System.exit(0);
}
private final String repos;
private final String txn;
private final String rev;
private SVNCommitInfo info;
private OMElement template;
private Configuration config;
private final String nss;
private final long startTime;
private ALFEmitter(CommandLine cmd, long startTime) {
this.startTime = startTime;
repos = cmd.getOptionValue(PARAM_REPOS);
txn = cmd.getOptionValue(PARAM_TXN);
rev = cmd.getOptionValue(PARAM_REV);
String config_file = cmd.getOptionValue(PARAM_CONFIG, "emitter.properties");
 
logger.debug(String.format("Using REPOS='%s' and TXN='%s'.", repos, txn));
config = null;
try {
config = new PropertiesConfiguration(config_file);
} catch (ConfigurationException e) {
logger.error("Could not find/ load '"+config_file+"' file.", e);
System.exit(1);
}
/*
* Load Properties from Configuration file
*/
//it might be interesting to look into SVNKit
//for a pure Java implementation in future
final String svnlook = config.getString("svnlook");
logger.debug("Using svnlook at '" + svnlook +"'.");
final String[] issuepatterns = config.getStringArray("issuepattern");
StringBuilder sb = new StringBuilder(); for(String s : issuepatterns) sb.append(s);
logger.debug(String.format("Using issue id patterns: '%s'.", sb.toString()));
final String eventtemplate = config.getString("eventtemplate");
logger.debug("Using alf event template at '" + eventtemplate +"'.");
nss = config.getString("eventnamespace", "http://www.eclipse.org/alf/schema/EventBase/1");
logger.debug("Using alf event namespace '" + nss +"'.");
final String marker_logmessage = config.getString("marker.logmessage", "@@logmessage@@");
logger.debug("Using comment marker '<!-- " + marker_logmessage +" -->' in event template for logmessage.");
final String marker_author = config.getString("marker.author", "@@author@@");
logger.debug("Using comment marker '<!-- " + marker_author +" -->' with event template for author.");
final String marker_addedfiles = config.getString("marker.addedfiles", "@@addedfiles@@");
logger.debug("Using comment marker '<!-- " + marker_addedfiles +" -->' with event template for files added during commit.");
final String marker_deletedfiles = config.getString("marker.deletedfiles", "@@deletedfiles@@");
logger.debug("Using comment marker '<!-- " + marker_deletedfiles +" -->' with event template for files deleted during commit.");
final String marker_changedfiles = config.getString("marker.changedfiles", "@@changedfiles@@");
logger.debug("Using comment marker '<!-- " + marker_changedfiles +" -->' with event template for files changed during commit.");
final String marker_fileselementname = config.getString("marker.fileselementname", "file");
logger.debug("Using element name '" +marker_fileselementname +"' to wrap files list.");
final String marker_issues = config.getString("marker.issues", "@@issues@@");
logger.debug("Using comment marker '<!-- " + marker_issues +" -->' with event template for issue list.");
final String marker_issueselementname = config.getString("marker.issueselementname", "issue");
logger.debug("Using element name '" +marker_issueselementname +"' to wrap issue list.");
final String eventmanager = config.getString("eventmanager");
logger.debug("Using eventmanager at '" +eventmanager +"'.");
final String eventmanager_user = config.getString("eventmanager.user");
final String eventmanager_pass = config.getString("eventmanager.password");
logger.debug("Using username '" +eventmanager_user +"' and a password.");
final boolean isSoapEnabled = config.getBoolean("isSoapEnabled", true);
logger.debug("Sending soap message is enabled='" +isSoapEnabled +"'.");
final boolean isDropResponse = config.getBoolean("isDropResponse", true);
logger.debug("Receiving the soap response is enabled='" +isDropResponse +"'.");
try {
template = OMXMLBuilderFactory.createOMBuilder(new FileInputStream(new File(eventtemplate)))
.getDocument().getOMDocumentElement();
} catch (FileNotFoundException e1) {
logger.error(String.format("Could not load XML event template from file '%s'.", eventtemplate), e1);
System.exit(1);
}
/*
*
*/
SVNLookExecutor exec = new SVNLookExecutor(new File(svnlook), repos);
if(cmd.hasOption(PARAM_TXN)) exec.setTXN(txn);
if(cmd.hasOption(PARAM_REV)) exec.setRev(rev);
info = exec.getCommitInfo();
info.parseIssues(issuepatterns);
logger.debug("SVNCommitInfo author: "+ info.getAuthor());
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String datestring = f.format(info.getDate());
datestring= datestring.substring(0, 26) + ":" + datestring.substring(26); //hack into ISO 8601 format
logger.debug("SVNCommitInfo date: "+ datestring);
logger.debug("SVNCommitInfo log message: "+ info.getLogmessage());
logger.debug("SVNCommitInfo file list: "+ info.getChangeFileListAsString());
/**
* Event XML Erzeugen
*/
try {
addElement( marker_logmessage, info.getLogmessage(), true);
addElement(marker_author, info.getAuthor(), false);
addElement("@@timestamp@@", datestring, false);
addElements(marker_changedfiles, info.getChangedFiles(), marker_fileselementname);
addElements(marker_deletedfiles, info.getDeletedFiles(), marker_fileselementname);
addElements(marker_addedfiles, info.getAddedFiles(), marker_fileselementname);
addElements(marker_issues, info.getIssues(), marker_issueselementname);
AXIOMXPath path = new AXIOMXPath("//bru1:User");
OMNamespace ns = template.findNamespace(nss, null);
path.addNamespace("bru1", nss);
OMElement n = (OMElement) path.selectSingleNode(template);
if(n== null) {
logger.warn( String.format("<User> element was not found in namespace '%s'. Cannot add ALFSecurity elements. This is required since SBM 10.1.x.", nss));
} else {
/*
* <ns:User>
<!--Optional:-->
<ns:ALFSecurity>
<ns:UsernameToken>
<ns:Username>admin</ns:Username>
<ns:Password></ns:Password>
</ns:UsernameToken>
</ns:ALFSecurity>
</ns:User>
*/
n.removeChildren();
OMFactory fac = n.getOMFactory();
fac.createOMComment(n, "Generated by SVN-ALFEmitter");
OMElement sec = fac.createOMElement("ALFSecurity", ns);
OMElement token = fac.createOMElement("UsernameToken", ns);
OMElement user = fac.createOMElement("Username", ns);
user.addChild( fac.createOMText(eventmanager_user));
OMElement pass = fac.createOMElement("Password", ns);
pass.addChild(fac.createOMText(eventmanager_pass, OMNode.CDATA_SECTION_NODE));
token.addChild( user );
token.addChild( pass);
sec.addChild(token);
n.addChild(sec);
}
path = new AXIOMXPath("//bru1:Base/bru1:EventId");
path.addNamespace("bru1", nss);
n = (OMElement) path.selectSingleNode(template);
if(n==null) {
logger.error("<Base> element in message is incomplete. <EventId> is missing.");
} else {
n.addChild( n.getOMFactory().createOMText(UUID.randomUUID().toString() ));
}
path = new AXIOMXPath("//bru1:Base/bru1:ObjectId");
path.addNamespace("bru1", nss);
n = (OMElement) path.selectSingleNode(template);
if(n==null) {
logger.error("<Base> element in message is incomplete. <ObjectId> is missing.");
} else {
n.addChild( n.getOMFactory().createOMText(info.getTxn() ));
}
 
StringWriter out = new StringWriter();
template.getParent().serialize(out);
out.flush();
String resultxml = out.getBuffer().toString();
logger.debug("ALFEvent result:\n"+resultxml);
if(isSoapEnabled) {
SimpleHttpEvent sender = new SimpleHttpEvent(eventmanager, resultxml);
sender.sendSoap(isDropResponse);
logger.debug(String.format("Sending/ receiving the soap message took '%s' milliseconds.", sender.getDuration()));
} else {
logger.warn("Sending soap message is deactivated.");
}
} catch (FileNotFoundException e) {
logger.error(e.getMessage(), e);
System.exit(1);
} catch (ClientProtocolException e) {
logger.error(e.getMessage(), e);
System.exit(1);
} catch (IOException e) {
logger.error(e.getMessage(), e);
System.exit(1);
} catch (XMLStreamException e) {
logger.error(e.getMessage(), e);
System.exit(1);
} catch (JaxenException e) {
logger.error(e.getMessage(), e);
System.exit(1);
} finally {
logger.debug("Total execution took '"+(System.currentTimeMillis()-startTime)+"' milliseconds.");
String forcefail = config.getString("forcefail", "");
if(forcefail.length()>0) {
logger.warn("Force fail is active. All commits will be blocked.");
System.exit(1);
}
}
}
private void addElement(String pattern, String newCdata, boolean wrapCDATA) throws JaxenException {
OMComment comment = findComment(pattern);
if(comment!=null) {
OMFactory fac = OMAbstractFactory.getOMFactory();
int type = OMNode.TEXT_NODE;
if(wrapCDATA) {
type = OMNode.CDATA_SECTION_NODE;
}
OMText text = fac.createOMText(newCdata, type);
comment.insertSiblingAfter(text);
}
}
private void addElements(String pattern, List<String> files, String elementName) throws JaxenException {
if(files.size()<=0) return;
OMComment comment = findComment(pattern);
if(comment!=null) {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace ns = template.findNamespace(nss, null);
if(ns == null) logger.error(String.format("The namespace '%s' is not defined in the template.", nss));
for(String s : files) {
OMElement e = fac.createOMElement(elementName, ns);
OMText text = fac.createOMText(s, OMNode.TEXT_NODE);
e.addChild(text);
comment.insertSiblingAfter(e);
}
}
}
private OMComment findComment(String pattern) throws JaxenException {
AXIOMXPath path = new AXIOMXPath("//comment()[. = '"+pattern+"'][1]");
//OMNamespace ns = template.findNamespace(nss, null);
path.addNamespace("bru1", nss);
OMComment n = (OMComment) path.selectSingleNode(template);
if(n!=null) return n;
logger.warn("Comment '"+pattern+"' was not found in the XML template.");
return null;
}
/*
private static OMComment findComment(OMElement element, String pattern) {
logger.trace( String.format("Searching for comment pattern '%s' in element with name '%s'.", pattern, element.getLocalName()));
Iterator iter = element.getChildren();
 
while(iter.hasNext()) {
Object o = iter.next();
if(o instanceof OMNode) {
OMNode node = ((OMNode)o);
switch (node.getType() ) {
case OMNode.COMMENT_NODE:
OMComment comment = ((OMComment)node);
String value = comment.getValue().trim();
if(value.equals(pattern)) {
logger.debug("Found comment '" + pattern + "' in event template.");
return comment;
}
break;
 
case OMNode.ELEMENT_NODE:
//traverse
OMComment result = findComment( (OMElement)node, pattern);
if(result!=null) return result;
break;
default:
break;
}
}
}
//logger.info("Comment '" + pattern + "' was not found in event template.");
return null;
}
*/
@SuppressWarnings("static-access")
private static Options getOptions() {
Option repository = OptionBuilder.withArgName( "repository" )
.hasArg()
.withLongOpt("repository")
.withDescription( "Path or URL to the SVN repository." )
.create( PARAM_REPOS );
repository.setRequired(true);
Option txn = OptionBuilder.withArgName( "transactionid" )
.hasArg()
.withLongOpt("transaction")
.withDescription( "The SVN transaction id to examine (TXN). You cannot combine txn with -rev. "
+ "When a txn is given, the repository path must be a local path.")
.create( PARAM_TXN );
Option rev = OptionBuilder.withArgName( "revision" )
.hasArg()
.withDescription( "A revision to examine. You cannot combine revision with -txn." )
.create( PARAM_REV );
Option config = OptionBuilder.withArgName( "config_file" )
.hasArg()
.withLongOpt("config")
.withDescription( "The configuration file to use. Defaults to 'emitter.properties'.")
.create( PARAM_CONFIG );
Options options = new Options();
options.addOption(repository);
options.addOption(txn);
options.addOption(rev);
options.addOption(config);
return options;
}
private static void printHelp() {
// automatically generate the help statement
HelpFormatter formatter = new HelpFormatter();
String header = "\nSVN-ALFEventEmitter " + version +", a SVN hook implemented in Java to emit Eclipse ALFEvents on commit.\n\n";
String footer = "Please send bug reports to bru@brutex.de.\n(c)2013 Brian Rosenberger";
formatter.printHelp("java -jar SVN-ALFEventEmitter", header, getOptions(), footer, true);
}
}
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/src/log4j.properties
0,0 → 1,15
 
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
 
# Print the date in ISO 8601 format
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c{2} - %m%n
 
# Print only messages of level WARN or above in the package com.foo.
log4j.logger.net.brutex=DEBUG
 
log4j.logger.org.apache.axiom=INFO
log4j.logger.org.apache.commons.configuration=INFO
log4j.logger.org.apache.http=INFO
 
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/SVN-ALFEventEmitter/trunk/.settings/org.eclipse.jdt.core.prefs
0,0 → 1,11
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property