Sunday, February 24, 2008

2008-02-24 Sunday

Today I enabled the Subversion repository option for the "PNW SOA Commons" project that is hosted on sourceforge.net - you can browse the directory structure here. Nothing checked-in yet - I've begun working on the directory layout and will hopefully have something to check-in later this week.

TikiWiki CMS/Groupware 1.9.10.1 released - changelog

Hat'tip to Ted Neward for recently posting about indeed.com and their ability to graph Job Trends. Here's a graph of SOA job trends that I ran:


Saturday, February 23, 2008

2008-02-23 Saturday

I installed the latest Hudson 1.184 release on Friday at a client site. We have been running a previous release (1.164) under Glassfish V2. It appears that 1.184 fails to deploy under Glassfish V2 - but I was able to get it running under Tomcat 6.0.x. Some of the recent Hudson development efforts include support for LDAP integration (1.166). There are some very cool improvements.


On Feb. 11th, the day the WS02 Registry 1.0 was released, I downloaded it and began evaluating it for a current client SOA project.

I recently have submitted two bugs to the WS02 Registry project:

REGISTRY-233: Basic Search is not working for words in the Description
Description
The Basic Search does not appear to find words that appear as part of a Description (for either a Resource or Collection).

The Basic Search does not appear to find words that are embedded as part of the name of a Resource or Collection

Developer's Comments
We are using tags as the main search mechanism in the registry. So the basic search only searches for tags. But it may also be useful to include description and the resource name in the search as you mentioned. We can discuss this in the mailing list and implement if necessary.

We are providing name based search in the advanced search. But we haven't implemented the description based search there yet. We will add it soon. Thanks for pointing this out.


and

REGISTRY-226: Deployment of wso2registry.war fails under Glassfish V2
Developer's Comments
I was able to recreate this issue with the Glassfish V2 - Sun Java System Application Server 9.1and Ubuntu 7.10,jdk1.5.0_08. Same NPE occurred in Linux environment as well.
(...)
As I can see the issue is due to pack and unpack of war. We tried to deploy axis2.war and same NPE occurs so I guess issues is not only in wso2regsitry.
(...)
We have found the issue , it is due to a compile error in

registry-resources-versions.jsp

So I we will fix that soon , thanks you very much for finding the issue and creating a jira





Link Harvest...enjoy

Zune Game Development with XNA Game Studio 3.0

QCon Panel: What will the Future of Java Development Be?

Microsoft Office Binary (doc, xls, ppt) File Formats

Mathematica and the O'Reilly School of Technology: An Interview with Scott Gray

Richard Feynman, the Challenger Disaster, and Software Engineering

Google funds Photoshop-on-Linux work

Interview and Book Excerpt: Nicolai Josuttis, "SOA in Practice"

JEE 6: Extensibility, Profiles and Pruning

An Agile Developer's Responsibility

Tips and Blogs for Project GlassFish

BluePrints Guidelines, Example apps and code for GlassFish

JAX-WS 2.1 and JAXB 2.1 is available in JDK 6 Update 4 release

glassfish: Index of Sample Applications

Java EE docs: Chapter 31 The Java Message Service API

ActiveMQ: Mirrored Queues

Creating Domain Specific Languages with Groovy

Bringing Scripting back to VB

VB 6 to VB.NET Migration Proceeds Ever So Slowly

Ideal Architecture is not always about Ideal Technology or Techniques

Leading Troubled Projects: Secure Your Own Oxygen Mask First

Custom MSBuild Tasks

Qi4j.org

Qi4j introduces Composite Oriented Programming
Qi4j is pronounced "chee for jay".

Qi4j is a framework for domain centric application development, including evolved concepts from AOP, DI and DDD

Qi4j is an implementation of Composite Oriented Programming, using the standard Java 5 platform, without the use of any pre-processors or new language elements

Thursday, February 21, 2008

2008-02-21 Thursday

In response to a recent blog post by Loraine Lawson SOA Governance Tools Simplified , I provided the following post as a comment:

I have recently conducted some preliminary testing of some open source Registry/Repository type tools for a client - that could be helpful for organizations that are looking to experiment first before paying big bucks for some vendor solution.

Yelo
http://freshmeat.net/projects/yelo/
"Yelo is a standalone service catalog for SOA (service-oriented architecture). A service catalog is an important part of the business process of service-oriented architecture and seems to be available today only as part of a larger package. This application is meant to foster a "marketplace" approach to services within an enterprise. "

Opinion: Not bad for a simple catalog. Could be easily extended. Better than a spreadsheet being passed around. Does not appear to be an active project. .NET implementation.


WS02 Registry - 1.0
http://wso2.org/projects/registry
WSO2 Registry enables you to store, catalog, index and manage your enterprise meta data in a simple, scalable and easy-to-use model. It is designed around community concepts such as tags, comments, ratings, users and roles.

WSO2 Registry can be considered a structured Wiki designed to help manage meta-data in a simple and a business-friendly manner. In addition, the registry allows storage of unstructured data such as Word documents and Excel spreadsheets. Using this approach, you can build a catalog of enterprise information ranging from services to service descriptions.

WSO2 Registry can be deployed in application servers and accessed using the Web UI or the APP interface. It can also be embedded as a Java library within Java programs that can then be used as a resource store with all community features and versioning.

WSO2 Registry is released under the Apache License v2.0

Storing and managing resources and collections
Tagging, commenting and rating resources
Managing users and roles
Authentication and authorization on all resources
Resource/collection versioning
Tag based search
Advanced search
Activity log and filtering support
APP based Remote Registry
Media type handling support
Web based user interface with Web 2.0 look and feel

Opinion: Recently released (Feb. 11th 2008) - has a nice UI - but there are some bugs that the development team needs to resolve. Worth monitoring this one as it develops further.



freebXML Registry - Omar 3.1 (ebXML reference implementation)
http://ebxmlrr.sourceforge.net/
Packed with features, thick and thin clients supported, Java implementation.

Opinion: The UI is not intuitive, seems a bit cluttered....but might be worth the effort to customize the UI if a team wanted a robust, feature-rich, tool.



Summary:
If you want to share information for a small set of web services - a Wiki might be a better approach over a spreadsheet. I've recently adopted TikiWiki for team design collaboration for a current SOA project.

http://info.tikiwiki.org/tiki-index.php



Loraine's original interview article (Before You Buy: Understanding SOA Governance Tools) with Gartner analyst Frank Kenney, who co-authored Gartner's Magic Quadrant for Integrated SOA Governance Technology Sets, released in December 2007,

Monday, February 18, 2008

2008-02-18 Monday

The always insightful and very entertaining Dr. Gernot Starke has a link on his blog to his arc42 template (Architecture Documentation Structure Overview).

Another article he has recently published: ORDNUNG 2.0 – HILFEN FÜR
DEN INFO-DSCHUNGEL?
discusses the relative merits of using a Tag approach to how one might organize files (and thereby make them easier to find) - versus using the historical folder hierarchy approach that is more commonly used (he cites the advent and usefulness of the "Tag Cloud" concept as an example of the obvious utility oof this altenative approach. [Reading the paper was also a good chance for me to practice reading German again]

I'm installing HydraIRC today to give it a try. Here's its wiki.

"HydraIRC is an open-source IRC client with an attractive and easy to use interface. It supports DCC Chat and File transfers, Connecting to Multiple IRC Servers, Docking/Floating Windows, DLL Plugins, Channel Monitoring, Message Logs, Logging, Output Themes, Color Schemes, Buddy Groups, Auto-Connect, One-Click Favorites and more.

Features
Connects to multiple servers.
DCC File Transfers and Chat windows.
Fully Customizable GUI Layout.
Channel Monitor.
Event Logging.


I came across the Open Clip Art Library tonight - and downloaded their 0.18 release of 6,900 images to add to my development library repository. (They have 6403 New Clip Art and 7000+ Archived Clip Art)


I've been reading through the JIRA Issue Tracker for the Drools (JBoss Rules) project this weekend. Looking for some possible simple bugs to tackle as a way of getting my feet wet as a contributor to the community.

I've also been monitoring the IRC discussions (irc.codehaus.org #drools) of the Drools Developer team - learning a bit more about the current development efforts, issues, and future directions of the Drools project.

Another interesting resource to explore is the Atlassian FishEye (source code repository insight) tool used by the Drools project.

Tonight I've been studying the DRL.g file from the drools-compiler (r-18245, Drools 4.0.x trunk development)
grammar DRL;

@parser::header {
package org.drools.lang;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.drools.lang.descr.*;
}

@parser::members {
private PackageDescr packageDescr;
private List errors = new ArrayList();
private String source = "unknown";
private int lineOffset = 0;
private DescrFactory factory = new DescrFactory();
private boolean parserDebug = false;
private Location location = new Location( Location.LOCATION_UNKNOWN );

// THE FOLLOWING LINES ARE DUMMY ATTRIBUTES TO WORK AROUND AN ANTLR BUG
private BaseDescr from = null;
private FieldConstraintDescr fc = null;
private RestrictionConnectiveDescr and = null;
private RestrictionConnectiveDescr or = null;
private ConditionalElementDescr base = null;

public void setParserDebug(boolean parserDebug) {
this.parserDebug = parserDebug;
}

public void debug(String message) {
if ( parserDebug )
System.err.println( "drl parser: " + message );
}

public void setSource(String source) {
this.source = source;
}
public DescrFactory getFactory() {
return factory;
}

public String getSource() {
return this.source;
}

public PackageDescr getPackageDescr() {
return packageDescr;
}

private int offset(int line) {
return line + lineOffset;
}

/**
* This will set the offset to record when reparsing. Normally is zero of course
*/
public void setLineOffset(int i) {
this.lineOffset = i;
}

private String getString(String token) {
return safeSubstring( token, 1, token.length() -1 );
}

private String cleanupSpaces( String input ) {
return input.replaceAll( "\\s", "" );
}


public void reportError(RecognitionException ex) {
// if we've already reported an error and have not matched a token
// yet successfully, don't report any errors.
if ( errorRecovery ) {
return;
}
errorRecovery = true;

ex.line = offset(ex.line); //add the offset if there is one
errors.add( ex );
}

/** return the raw RecognitionException errors */
public List getErrors() {
return errors;
}

/** Return a list of pretty strings summarising the errors */
public List getErrorMessages() {
List messages = new ArrayList();
for ( Iterator errorIter = errors.iterator() ; errorIter.hasNext() ; ) {
messages.add( createErrorMessage( (RecognitionException) errorIter.next() ) );
}
return messages;
}

/** return true if any parser errors were accumulated */
public boolean hasErrors() {
return ! errors.isEmpty();
}

/** This will take a RecognitionException, and create a sensible error message out of it */
public String createErrorMessage(RecognitionException e)
{
StringBuffer message = new StringBuffer();
message.append( source + ":"+e.line+":"+e.charPositionInLine+" ");
if ( e instanceof MismatchedTokenException ) {
MismatchedTokenException mte = (MismatchedTokenException)e;
if( mte.expecting >=0 && mte.expecting < tokenNames.length ) {
message.append("mismatched token: "+
e.token+
"; expecting type "+
tokenNames[mte.expecting]);
} else {
message.append("mismatched token: "+
e.token+
";");
}
}
else if ( e instanceof MismatchedTreeNodeException ) {
MismatchedTreeNodeException mtne = (MismatchedTreeNodeException)e;
if( mtne.expecting >=0 && mtne.expecting < tokenNames.length ) {
message.append("mismatched tree node: "+
mtne.toString() +
"; expecting type "+
tokenNames[mtne.expecting]);
} else {
message.append("mismatched tree node: "+
mtne.toString() +
";");
}
}
else if ( e instanceof NoViableAltException ) {
NoViableAltException nvae = (NoViableAltException)e;
message.append( "Unexpected token '" + e.token.getText() + "'" );
/*
message.append("decision=<<"+nvae.grammarDecisionDescription+">>"+
" state "+nvae.stateNumber+
" (decision="+nvae.decisionNumber+
") no viable alt; token="+
e.token);
*/
}
else if ( e instanceof EarlyExitException ) {
EarlyExitException eee = (EarlyExitException)e;
message.append("required (...)+ loop (decision="+
eee.decisionNumber+
") did not match anything; token="+
e.token);
}
else if ( e instanceof MismatchedSetException ) {
MismatchedSetException mse = (MismatchedSetException)e;
message.append("mismatched token '"+
e.token+
"' expecting set "+mse.expecting);
}
else if ( e instanceof MismatchedNotSetException ) {
MismatchedNotSetException mse = (MismatchedNotSetException)e;
message.append("mismatched token '"+
e.token+
"' expecting set "+mse.expecting);
}
else if ( e instanceof FailedPredicateException ) {
FailedPredicateException fpe = (FailedPredicateException)e;
message.append("rule "+fpe.ruleName+" failed predicate: {"+
fpe.predicateText+"}?");
} else if (e instanceof GeneralParseException) {
message.append(" " + e.getMessage());
}
return message.toString();
}

void checkTrailingSemicolon(String text, int line) {
if (text.trim().endsWith( ";" ) ) {
this.errors.add( new GeneralParseException( "Trailing semi-colon not allowed", offset(line) ) );
}
}

public Location getLocation() {
return this.location;
}

private String safeSubstring( String text, int start, int end ) {
return text.substring( Math.min( start, text.length() ), Math.min( Math.max( start, end ), text.length() ) );
}

}

@lexer::header {
package org.drools.lang;
}

opt_semicolon
: ';'?
;

compilation_unit
@init {
// reset Location information
this.location = new Location( Location.LOCATION_UNKNOWN );
}
: prolog
statement*
EOF
;
catch [ RecognitionException e ] {
reportError( e );
}

prolog
@init {
String packageName = "";
}
: ( pkgstmt=package_statement { packageName = $pkgstmt.packageName; } )?
{
this.packageDescr = factory.createPackage( packageName );
}
;


statement
: a=rule_attribute { this.packageDescr.addAttribute( a ); }
| function_import_statement
| event_import_statement
| import_statement
| global
| function
| t=template { this.packageDescr.addFactTemplate( $t.template ); }
| r=rule { this.packageDescr.addRule( $r.rule ); }
| q=query { this.packageDescr.addRule( $q.query ); }
;

package_statement returns [String packageName]
@init{
$packageName = null;
}
:
PACKAGE n=dotted_name opt_semicolon
{
$packageName = $n.text;
}
;



import_statement
@init {
ImportDescr importDecl = null;
}
: IMPORT
{
importDecl = factory.createImport( );
importDecl.setStartCharacter( ((CommonToken)$IMPORT).getStartIndex() );
if (packageDescr != null) {
packageDescr.addImport( importDecl );
}
}
import_name[importDecl] opt_semicolon
;

function_import_statement
@init {
FunctionImportDescr importDecl = null;
}
: IMPORT FUNCTION
{
importDecl = factory.createFunctionImport();
importDecl.setStartCharacter( ((CommonToken)$IMPORT).getStartIndex() );
if (packageDescr != null) {
packageDescr.addFunctionImport( importDecl );
}
}
import_name[importDecl] opt_semicolon
;

event_import_statement
@init {
ImportDescr importDecl = null;
}
: IMPORT EVENT
{
importDecl = factory.createEventImport( );
importDecl.setStartCharacter( ((CommonToken)$IMPORT).getStartIndex() );
if (packageDescr != null) {
packageDescr.addImport( importDecl );
}
}
import_name[importDecl] opt_semicolon
;


import_name[ImportDescr importDecl] returns [String name]
@init {
$name = null;
}
:
ID
{
$name=$ID.text;
$importDecl.setTarget( name );
$importDecl.setEndCharacter( ((CommonToken)$ID).getStopIndex() );
}
( DOT id=identifier
{
$name = $name + $DOT.text + $id.text;
$importDecl.setTarget( $name );
$importDecl.setEndCharacter( ((CommonToken)$id.start).getStopIndex() );
}
)*
( star='.*'
{
$name = $name + $star.text;
$importDecl.setTarget( $name );
$importDecl.setEndCharacter( ((CommonToken)$star).getStopIndex() );
}
)?
;


global
@init {
GlobalDescr global = null;
}
:
GLOBAL
{
global = factory.createGlobal();
global.setStartCharacter( ((CommonToken)$GLOBAL).getStartIndex() );
packageDescr.addGlobal( global );
}
type=dotted_name
{
global.setType( $type.text );
}
id=identifier opt_semicolon
{
global.setIdentifier( $id.text );
global.setEndCharacter( ((CommonToken)$id.start).getStopIndex() );
}
;


function
@init {
FunctionDescr f = null;
String type = null;
}
:
FUNCTION retType=dotted_name? id=identifier
{
//System.err.println( "function :: " + n.getText() );
type = retType != null ? $retType.text : null;
f = factory.createFunction( $id.text, type );
f.setLocation(offset($FUNCTION.line), $FUNCTION.pos);
f.setStartCharacter( ((CommonToken)$FUNCTION).getStartIndex() );
packageDescr.addFunction( f );
}
LEFT_PAREN
( paramType=dotted_name? paramName=argument
{
type = paramType != null ? $paramType.text : null;
f.addParameter( type, $paramName.name );
}
( COMMA paramType=dotted_name? paramName=argument
{
type = paramType != null ? $paramType.text : null;
f.addParameter( type, $paramName.name );
}
)*
)?
RIGHT_PAREN
body=curly_chunk
{
//strip out '{','}'
f.setText( safeSubstring( $body.text, 1, $body.text.length()-1 ) );
f.setEndCharacter( ((CommonToken)$body.stop).getStopIndex() );
f.setEndLocation(offset($body.stop.getLine()), $body.stop.getCharPositionInLine());
}
;

argument returns [String name]
@init {
$name = null;
}
: id=identifier { $name=$id.text; } ( '[' ']' { $name += "[]";})*
;



query returns [QueryDescr query]
@init {
$query = null;
AndDescr lhs = null;
List params = null;
List types = null;

}
:
QUERY queryName=name
{
$query = factory.createQuery( $queryName.name );
$query.setLocation( offset($QUERY.line), $QUERY.pos );
$query.setStartCharacter( ((CommonToken)$QUERY).getStartIndex() );
lhs = new AndDescr(); $query.setLhs( lhs );
lhs.setLocation( offset($QUERY.line), $QUERY.pos );
location.setType( Location.LOCATION_RULE_HEADER );
}
( LEFT_PAREN
( { params = new ArrayList(); types = new ArrayList();}

(paramType=qualified_id? paramName=ID { params.add( $paramName.text ); String type = (paramType != null) ? $paramType.text : "Object"; types.add( type ); } )
(COMMA paramType=qualified_id? paramName=ID { params.add( $paramName.text ); String type = (paramType != null) ? $paramType.text : "Object"; types.add( type ); } )*

{ $query.setParameters( (String[]) params.toArray( new String[params.size()] ) );
$query.setParameterTypes( (String[]) types.toArray( new String[types.size()] ) );
}
)?
RIGHT_PAREN
)?
{
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
}
normal_lhs_block[lhs]
END opt_semicolon
{
$query.setEndCharacter( ((CommonToken)$END).getStopIndex() );
}
;

template returns [FactTemplateDescr template]
@init {
$template = null;
}
:
TEMPLATE templateName=name opt_semicolon
{
$template = new FactTemplateDescr($templateName.name);
$template.setLocation( offset($TEMPLATE.line), $TEMPLATE.pos );
$template.setStartCharacter( ((CommonToken)$TEMPLATE).getStartIndex() );
}
(
slot=template_slot
{
template.addFieldTemplate( $slot.field );
}
)+
END opt_semicolon
{
template.setEndCharacter( ((CommonToken)$END).getStopIndex() );
}
;

template_slot returns [FieldTemplateDescr field]
@init {
$field = null;
}
:
{
$field = factory.createFieldTemplate();
}
fieldType=qualified_id
{
$field.setClassType( $fieldType.text );
$field.setStartCharacter( ((CommonToken)$fieldType.start).getStartIndex() );
$field.setEndCharacter( ((CommonToken)$fieldType.stop).getStopIndex() );
}

id=identifier opt_semicolon
{
$field.setName( $id.text );
$field.setLocation( offset($id.start.getLine()), $id.start.getCharPositionInLine() );
$field.setEndCharacter( ((CommonToken)$id.start).getStopIndex() );
}
;

rule returns [RuleDescr rule]
@init {
$rule = null;
AndDescr lhs = null;
}
:
RULE ruleName=name
{
location.setType( Location.LOCATION_RULE_HEADER );
debug( "start rule: " + $ruleName.name );
$rule = new RuleDescr( $ruleName.name, null );
$rule.setLocation( offset($RULE.line), $RULE.pos );
$rule.setStartCharacter( ((CommonToken)$RULE).getStartIndex() );
lhs = new AndDescr();
$rule.setLhs( lhs );
}
rule_attributes[$rule]?
(
WHEN ':'?
{
this.location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
lhs.setLocation( offset($WHEN.line), $WHEN.pos );
lhs.setStartCharacter( ((CommonToken)$WHEN).getStartIndex() );
}
normal_lhs_block[lhs]
)?
rhs_chunk[$rule]
;



rule_attributes[RuleDescr rule]
:
( ATTRIBUTES ':' )?
attr=rule_attribute { $rule.addAttribute( $attr.attr ); }
( ','? attr=rule_attribute { $rule.addAttribute( $attr.attr ); } )*
;



rule_attribute returns [AttributeDescr attr]
@init {
$attr = null;
}
@after {
$attr = $a.descr;
}
: a=salience
| a=no_loop
| a=agenda_group
| a=duration
| a=activation_group
| a=auto_focus
| a=date_effective
| a=date_expires
| a=enabled
| a=ruleflow_group
| a=lock_on_active
| a=dialect
;

date_effective returns [AttributeDescr descr]
@init {
$descr = null;
}
:
DATE_EFFECTIVE STRING
{
$descr = new AttributeDescr( "date-effective", getString( $STRING.text ) );
$descr.setLocation( offset( $DATE_EFFECTIVE.line ), $DATE_EFFECTIVE.pos );
$descr.setStartCharacter( ((CommonToken)$DATE_EFFECTIVE).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$STRING).getStopIndex() );
}

;

date_expires returns [AttributeDescr descr]
@init {
$descr = null;
}
: DATE_EXPIRES STRING
{
$descr = new AttributeDescr( "date-expires", getString( $STRING.text ) );
$descr.setLocation( offset($DATE_EXPIRES.line), $DATE_EXPIRES.pos );
$descr.setStartCharacter( ((CommonToken)$DATE_EXPIRES).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$STRING).getStopIndex() );
}
;

enabled returns [AttributeDescr descr]
@init {
$descr = null;
}
: ENABLED BOOL
{
$descr = new AttributeDescr( "enabled", $BOOL.text );
$descr.setLocation( offset($ENABLED.line), $ENABLED.pos );
$descr.setStartCharacter( ((CommonToken)$ENABLED).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$BOOL).getStopIndex() );
}
;

salience returns [AttributeDescr descr]
@init {
$descr = null;
}
:
SALIENCE
{
$descr = new AttributeDescr( "salience" );
$descr.setLocation( offset($SALIENCE.line), $SALIENCE.pos );
$descr.setStartCharacter( ((CommonToken)$SALIENCE).getStartIndex() );
}
( INT
{
$descr.setValue( $INT.text );
$descr.setEndCharacter( ((CommonToken)$INT).getStopIndex() );
}
| txt=paren_chunk
{
$descr.setValue( $txt.text );
$descr.setEndCharacter( ((CommonToken)$txt.stop).getStopIndex() );
}
)
;

no_loop returns [AttributeDescr descr]
@init {
$descr = null;
}
: NO_LOOP
{
$descr = new AttributeDescr( "no-loop", "true" );
$descr.setLocation( offset($NO_LOOP.line), $NO_LOOP.pos );
$descr.setStartCharacter( ((CommonToken)$NO_LOOP).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$NO_LOOP).getStopIndex() );
}
( BOOL
{
$descr.setValue( $BOOL.text );
$descr.setEndCharacter( ((CommonToken)$BOOL).getStopIndex() );
}
)?
;

auto_focus returns [AttributeDescr descr]
@init {
$descr = null;
}
: AUTO_FOCUS
{
$descr = new AttributeDescr( "auto-focus", "true" );
$descr.setLocation( offset($AUTO_FOCUS.line), $AUTO_FOCUS.pos );
$descr.setStartCharacter( ((CommonToken)$AUTO_FOCUS).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$AUTO_FOCUS).getStopIndex() );
}
( BOOL
{
$descr.setValue( $BOOL.text );
$descr.setEndCharacter( ((CommonToken)$BOOL).getStopIndex() );
}
)?
;

activation_group returns [AttributeDescr descr]
@init {
$descr = null;
}
: ACTIVATION_GROUP STRING
{
$descr = new AttributeDescr( "activation-group", getString( $STRING.text ) );
$descr.setLocation( offset($ACTIVATION_GROUP.line), $ACTIVATION_GROUP.pos );
$descr.setStartCharacter( ((CommonToken)$ACTIVATION_GROUP).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$STRING).getStopIndex() );
}
;

ruleflow_group returns [AttributeDescr descr]
@init {
$descr = null;
}
: RULEFLOW_GROUP STRING
{
$descr = new AttributeDescr( "ruleflow-group", getString( $STRING.text ) );
$descr.setLocation( offset($RULEFLOW_GROUP.line), $RULEFLOW_GROUP.pos );
$descr.setStartCharacter( ((CommonToken)$RULEFLOW_GROUP).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$STRING).getStopIndex() );
}
;

agenda_group returns [AttributeDescr descr]
@init {
$descr = null;
}
: AGENDA_GROUP STRING
{
$descr = new AttributeDescr( "agenda-group", getString( $STRING.text ) );
$descr.setLocation( offset($AGENDA_GROUP.line), $AGENDA_GROUP.pos );
$descr.setStartCharacter( ((CommonToken)$AGENDA_GROUP).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$STRING).getStopIndex() );
}
;

duration returns [AttributeDescr descr]
@init {
$descr = null;
}
: DURATION INT
{
$descr = new AttributeDescr( "duration", $INT.text );
$descr.setLocation( offset($DURATION.line), $DURATION.pos );
$descr.setStartCharacter( ((CommonToken)$DURATION).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$INT).getStopIndex() );
}
;

dialect returns [AttributeDescr descr]
@init {
$descr = null;
}
: DIALECT STRING
{
$descr = new AttributeDescr( "dialect", getString( $STRING.text ) );
$descr.setLocation( offset($DIALECT.line), $DIALECT.pos );
$descr.setStartCharacter( ((CommonToken)$DIALECT).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$STRING).getStopIndex() );
}
;

lock_on_active returns [AttributeDescr descr]
@init {
$descr = null;
}
: LOCK_ON_ACTIVE
{
$descr = new AttributeDescr( "lock-on-active", "true" );
$descr.setLocation( offset($LOCK_ON_ACTIVE.line), $LOCK_ON_ACTIVE.pos );
$descr.setStartCharacter( ((CommonToken)$LOCK_ON_ACTIVE).getStartIndex() );
$descr.setEndCharacter( ((CommonToken)$LOCK_ON_ACTIVE).getStopIndex() );
}
( BOOL
{
$descr.setValue( $BOOL.text );
$descr.setEndCharacter( ((CommonToken)$BOOL).getStopIndex() );
}
)?
;

normal_lhs_block[AndDescr descr]
@init {
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
}
:
( d=lhs[$descr]
{ if( $d.d != null) $descr.addDescr( $d.d ); }
)*
;


lhs[ConditionalElementDescr ce] returns [BaseDescr d]
@init {
$d=null;
}
: l=lhs_or { $d = $l.d; }
;


lhs_or returns [BaseDescr d]
@init{
$d = null;
OrDescr or = null;
}
: LEFT_PAREN OR
{
or = new OrDescr();
$d = or;
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION_AND_OR );
}
( lhsand=lhs_and
{
or.addDescr( $lhsand.d );
})+
RIGHT_PAREN // PREFIX
|
left=lhs_and { $d = $left.d; }
( (OR|DOUBLE_PIPE)
{
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION_AND_OR );
}
right=lhs_and
{
if ( or == null ) {
or = new OrDescr();
or.addDescr( $left.d );
$d = or;
}

or.addDescr( $right.d );
}
)*
;

lhs_and returns [BaseDescr d]
@init{
$d = null;
AndDescr and = null;
}
: LEFT_PAREN AND
{
and = new AndDescr();
$d = and;
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION_AND_OR );
}
(lhsunary=lhs_unary
{
and.addDescr( $lhsunary.d );
})+
RIGHT_PAREN
|
left=lhs_unary { $d = $left.d; }
( (AND|DOUBLE_AMPER)
{
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION_AND_OR );
}
right=lhs_unary
{
if ( and == null ) {
and = new AndDescr();
and.addDescr( $left.d );
$d = and;
}

and.addDescr( $right.d );
}
)*
;

lhs_unary returns [BaseDescr d]
@init {
$d = null;
}
: ( ( EXISTS ) => u=lhs_exist { $d = $u.d; }
| ( NOT ) => u=lhs_not { $d = $u.d; }
| ( EVAL ) => u=lhs_eval { $d = $u.d; }
| ( FORALL ) => u=lhs_forall { $d = $u.d; }
| ( LEFT_PAREN ) => LEFT_PAREN u=lhs_or RIGHT_PAREN { $d = $u.d; }
| ps=pattern_source { $d = (BaseDescr) $ps.d; }
)
opt_semicolon
;

pattern_source returns [BaseDescr d]
@init {
$d = null;
}
:
u=lhs_pattern { $d = $u.d; }
(
// THIS IS SIMPLY DUMB IMO, but it was the only way I could make it work... :( not sure if it is an
// ANTLR bug or if I'm doing something wrong.
( (FROM ENTRY_POINT) => FROM ep=entrypoint_statement { if( $d != null ) ((PatternDescr)$d).setSource((PatternSourceDescr) $ep.d); })
|
FROM
{
location.setType(Location.LOCATION_LHS_FROM);
location.setProperty(Location.LOCATION_FROM_CONTENT, "");
}
( options { k=1; backtrack=true;} :
( ac=accumulate_statement { if( $d != null ) ((PatternDescr)$d).setSource((PatternSourceDescr) $ac.d); })
| ( cs=collect_statement { if( $d != null ) ((PatternDescr)$d).setSource((PatternSourceDescr) $cs.d); })
//| ( ep=entrypoint_statement { if( $d != null ) ((PatternDescr)$d).setSource((PatternSourceDescr) $ep.d); })
| ( fm=from_statement { if( $d != null ) ((PatternDescr)$d).setSource((PatternSourceDescr) $fm.d); })
)
)?
;

lhs_exist returns [BaseDescr d]
@init {
$d = null;
}
: EXISTS
{
$d = new ExistsDescr( );
$d.setLocation( offset($EXISTS.line), $EXISTS.pos );
$d.setStartCharacter( ((CommonToken)$EXISTS).getStartIndex() );
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION_EXISTS );
}
( ( LEFT_PAREN or=lhs_or
{ if ( $or.d != null ) ((ExistsDescr)$d).addDescr( $or.d ); }
RIGHT_PAREN
{ $d.setEndCharacter( ((CommonToken)$RIGHT_PAREN).getStopIndex() ); }
)
| pattern=lhs_pattern
{
if ( $pattern.d != null ) {
((ExistsDescr)$d).addDescr( $pattern.d );
$d.setEndCharacter( $pattern.d.getEndCharacter() );
}
}
)
;

lhs_not returns [NotDescr d]
@init {
$d = null;
}
: NOT
{
$d = new NotDescr( );
$d.setLocation( offset($NOT.line), $NOT.pos );
$d.setStartCharacter( ((CommonToken)$NOT).getStartIndex() );
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION_NOT );
}
( ( LEFT_PAREN or=lhs_or
{ if ( $or.d != null ) $d.addDescr( $or.d ); }
RIGHT_PAREN
{ $d.setEndCharacter( ((CommonToken)$RIGHT_PAREN).getStopIndex() ); }
)
|
pattern=lhs_pattern
{
if ( $pattern.d != null ) {
$d.addDescr( $pattern.d );
$d.setEndCharacter( $pattern.d.getEndCharacter() );
}
}
)
;

lhs_eval returns [BaseDescr d]
@init {
$d = new EvalDescr( );
}
:
EVAL
{
location.setType( Location.LOCATION_LHS_INSIDE_EVAL );
}
c=paren_chunk
{
$d.setStartCharacter( ((CommonToken)$EVAL).getStartIndex() );
if( $c.text != null ) {
this.location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
String body = safeSubstring( $c.text, 1, $c.text.length()-1 );
checkTrailingSemicolon( body, offset($EVAL.line) );
((EvalDescr) $d).setContent( body );
location.setProperty(Location.LOCATION_EVAL_CONTENT, body);
}
if( $c.stop != null ) {
$d.setEndCharacter( ((CommonToken)$c.stop).getStopIndex() );
}
}
;

lhs_forall returns [ForallDescr d]
@init {
$d = factory.createForall();
}
: FORALL LEFT_PAREN base=lhs_pattern
{
$d.setStartCharacter( ((CommonToken)$FORALL).getStartIndex() );
// adding the base pattern
$d.addDescr( $base.d );
$d.setLocation( offset($FORALL.line), $FORALL.pos );
}
( pattern=lhs_pattern
{
// adding additional patterns
$d.addDescr( $pattern.d );
}
)*
RIGHT_PAREN
{
$d.setEndCharacter( ((CommonToken)$RIGHT_PAREN).getStopIndex() );
}
;

lhs_pattern returns [BaseDescr d]
@init {
$d=null;
}
@after {
$d=$f.d;
}
: f=fact_binding
| f=fact[null]
;

from_statement returns [FromDescr d]
@init {
$d=factory.createFrom();
}
:
ds=from_source[$d]
{
$d.setDataSource( $ds.ds );
}
;


accumulate_statement returns [AccumulateDescr d]
@init {
$d = factory.createAccumulate();
}
:
ACCUMULATE
{
$d.setLocation( offset($ACCUMULATE.line), $ACCUMULATE.pos );
$d.setStartCharacter( ((CommonToken)$ACCUMULATE).getStartIndex() );
location.setType( Location.LOCATION_LHS_FROM_ACCUMULATE );
}
LEFT_PAREN inputCE=lhs_or COMMA?
{
$d.setInput( $inputCE.d );
}
( (
INIT
{
location.setType( Location.LOCATION_LHS_FROM_ACCUMULATE_INIT );
}
text=paren_chunk COMMA?
{
if( $text.text != null ) {
$d.setInitCode( safeSubstring( $text.text, 1, $text.text.length()-1 ) );
location.setProperty(Location.LOCATION_PROPERTY_FROM_ACCUMULATE_INIT_CONTENT, $d.getInitCode());
location.setType( Location.LOCATION_LHS_FROM_ACCUMULATE_ACTION );
}
}
ACTION text=paren_chunk COMMA?
{
if( $text.text != null ) {
$d.setActionCode( safeSubstring( $text.text, 1, $text.text.length()-1 ) );
location.setProperty(Location.LOCATION_PROPERTY_FROM_ACCUMULATE_ACTION_CONTENT, $d.getActionCode());
location.setType( Location.LOCATION_LHS_FROM_ACCUMULATE_REVERSE );
}
}
( REVERSE text=paren_chunk COMMA?
{
if( $text.text != null ) {
$d.setReverseCode( safeSubstring( $text.text, 1, $text.text.length()-1 ) );
location.setProperty(Location.LOCATION_PROPERTY_FROM_ACCUMULATE_REVERSE_CONTENT, $d.getReverseCode());
location.setType( Location.LOCATION_LHS_FROM_ACCUMULATE_RESULT );
}
}
)?
RESULT text=paren_chunk
{
if( $text.text != null ) {
$d.setResultCode( safeSubstring( $text.text, 1, $text.text.length()-1 ) );
location.setProperty(Location.LOCATION_PROPERTY_FROM_ACCUMULATE_RESULT_CONTENT, $d.getResultCode());
}
}
)
|
(
id=ID text=paren_chunk
{
if( $id.text != null ) {
$d.setExternalFunction( true );
$d.setFunctionIdentifier( $id.text );
}
if( $text.text != null ) {
$d.setExpression( safeSubstring( $text.text, 1, $text.text.length()-1 ) );
location.setProperty(Location.LOCATION_PROPERTY_FROM_ACCUMULATE_EXPRESSION_CONTENT, $d.getExpression());
}
}
)
)
RIGHT_PAREN
{
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
d.setEndCharacter( ((CommonToken)$RIGHT_PAREN).getStopIndex() );
}
;

from_source[FromDescr from] returns [DeclarativeInvokerDescr ds]
@init {
$ds = null;
AccessorDescr ad = null;
FunctionCallDescr fc = null;
}
: ident=identifier
{
ad = new AccessorDescr(ident.start.getText());
ad.setLocation( offset(ident.start.getLine()), ident.start.getCharPositionInLine() );
ad.setStartCharacter( ((CommonToken)ident.start).getStartIndex() );
ad.setEndCharacter( ((CommonToken)ident.start).getStopIndex() );
$ds = ad;
location.setProperty(Location.LOCATION_FROM_CONTENT, ident.start.getText());
}
( /* WARNING: $o : O() from x(y) could be also $o : O() from x followed
by (y). Resolve by always forcing (...) to be paren_chunk if
after a from. Setting k=1 will force this to happen. No backtracking
but you'll get a warning from ANTLR. ANTLR resolves by choosing first
alternative to win, which is the paren_chunk case not the loop exit.
*/
options {k=1;}
: args=paren_chunk
{
if( $args.text != null ) {
ad.setVariableName( null );
fc = new FunctionCallDescr($ident.start.getText());
fc.setLocation( offset($ident.start.getLine()), $ident.start.getCharPositionInLine() );
fc.setArguments($args.text);
fc.setStartCharacter( ((CommonToken)$ident.start).getStartIndex() );
fc.setEndCharacter( ((CommonToken)$ident.start).getStopIndex() );
location.setProperty(Location.LOCATION_FROM_CONTENT, $args.text);
$from.setEndCharacter( ((CommonToken)$args.stop).getStopIndex() );
}
}
)?
expression_chain[$from, ad]?
;
finally {
if( ad != null ) {
if( fc != null ) {
ad.addFirstInvoker( fc );
}
location.setProperty(Location.LOCATION_FROM_CONTENT, ad.toString() );
}
}

expression_chain[FromDescr from, AccessorDescr as]
@init {
FieldAccessDescr fa = null;
MethodAccessDescr ma = null;
}
:
( DOT field=identifier
{
fa = new FieldAccessDescr($field.start.getText());
fa.setLocation( offset($field.start.getLine()), $field.start.getCharPositionInLine() );
fa.setStartCharacter( ((CommonToken)$field.start).getStartIndex() );
fa.setEndCharacter( ((CommonToken)$field.start).getStopIndex() );
}
(
( LEFT_SQUARE ) => sqarg=square_chunk
{
fa.setArgument( $sqarg.text );
$from.setEndCharacter( ((CommonToken)$sqarg.stop).getStopIndex() );
}
|
( LEFT_PAREN ) => paarg=paren_chunk
{
ma = new MethodAccessDescr( $field.start.getText(), $paarg.text );
ma.setLocation( offset($field.start.getLine()), $field.start.getCharPositionInLine() );
ma.setStartCharacter( ((CommonToken)$field.start).getStartIndex() );
$from.setEndCharacter( ((CommonToken)$paarg.stop).getStopIndex() );
}
)?
expression_chain[from, as]?
)
;
finally {
// must be added to the start, since it is a recursive rule
if( ma != null ) {
$as.addFirstInvoker( ma );
} else {
$as.addFirstInvoker( fa );
}
}



collect_statement returns [CollectDescr d]
@init {
$d = factory.createCollect();
}
:
COLLECT
{
$d.setLocation( offset($COLLECT.line), $COLLECT.pos );
$d.setStartCharacter( ((CommonToken)$COLLECT).getStartIndex() );
location.setType( Location.LOCATION_LHS_FROM_COLLECT );
}
LEFT_PAREN pattern=pattern_source RIGHT_PAREN
{
$d.setInputPattern( (PatternDescr) $pattern.d );
$d.setEndCharacter( ((CommonToken)$RIGHT_PAREN).getStopIndex() );
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
}
;

entrypoint_statement returns [EntryPointDescr d]
@init {
$d = factory.createEntryPoint();
}
:
ENTRY_POINT
{
$d.setLocation( offset($ENTRY_POINT.line), $ENTRY_POINT.pos );
$d.setStartCharacter( ((CommonToken)$ENTRY_POINT).getStartIndex() );
location.setType( Location.LOCATION_LHS_FROM_ENTRY_POINT );
}
id=name
{
$d.setEntryId( $id.name );
$d.setEndCharacter( ((CommonToken)$id.stop).getStopIndex() );
location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
}
;

fact_binding returns [BaseDescr d]
@init {
$d=null;
OrDescr or = null;
}
:
ID ':'
{
// handling incomplete parsing
$d = new PatternDescr( );
((PatternDescr) $d).setIdentifier( $ID.text );
}
( fe=fact[$ID.text]
{
// override previously instantiated pattern
$d=$fe.d;
if( $d != null ) {
$d.setStartCharacter( ((CommonToken)$ID).getStartIndex() );
}
}
|
LEFT_PAREN left=fact[$ID.text]
{
// override previously instantiated pattern
$d=$left.d;
if( $d != null ) {
$d.setStartCharacter( ((CommonToken)$ID).getStartIndex() );
}
}
( (OR|DOUBLE_PIPE)
right=fact[$ID.text]
{
if ( or == null ) {
or = new OrDescr();
or.addDescr( $left.d );
$d = or;
}
or.addDescr( $right.d );
}
)*
RIGHT_PAREN
)
;

fact[String ident] returns [BaseDescr d]
@init {
$d=null;
PatternDescr pattern = null;
}
:
{
pattern = new PatternDescr( );
if( $ident != null ) {
pattern.setIdentifier( $ident );
}
$d = pattern;
}
id=qualified_id
{
if( id != null ) {
pattern.setObjectType( $id.text );
pattern.setEndCharacter( -1 );
pattern.setStartCharacter( ((CommonToken)$id.start).getStartIndex() );
}
}
LEFT_PAREN
{
location.setType( Location.LOCATION_LHS_INSIDE_CONDITION_START );
location.setProperty( Location.LOCATION_PROPERTY_CLASS_NAME, $id.text );

pattern.setLocation( offset($LEFT_PAREN.line), $LEFT_PAREN.pos );
pattern.setLeftParentCharacter( ((CommonToken)$LEFT_PAREN).getStartIndex() );
}
constraints[pattern]?
RIGHT_PAREN
{
if( ")".equals( $RIGHT_PAREN.text ) ) {
this.location.setType( Location.LOCATION_LHS_BEGIN_OF_CONDITION );
pattern.setEndLocation( offset($RIGHT_PAREN.line), $RIGHT_PAREN.pos );
pattern.setEndCharacter( ((CommonToken)$RIGHT_PAREN).getStopIndex() );
pattern.setRightParentCharacter( ((CommonToken)$RIGHT_PAREN).getStartIndex() );
}
}
EOF? // this is needed for partial parsing
;


constraints[PatternDescr pattern]
: constraint[$pattern]
( COMMA { location.setType( Location.LOCATION_LHS_INSIDE_CONDITION_START ); }
constraint[$pattern]
)*
;

constraint[PatternDescr pattern]
@init {
ConditionalElementDescr top = null;
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_START);
location.setProperty(Location.LOCATION_PROPERTY_PROPERTY_NAME, input.LT(1).getText() );
}
:
{
top = $pattern.getConstraint();
}
or_constr[top]
;

or_constr[ConditionalElementDescr base]
@init {
OrDescr or = new OrDescr();
}
:
and_constr[or]
( DOUBLE_PIPE
{
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_START);
}
and_constr[or]
)*
{
if( or.getDescrs().size() == 1 ) {
$base.addOrMerge( (BaseDescr) or.getDescrs().get(0) );
} else if ( or.getDescrs().size() > 1 ) {
$base.addDescr( or );
}
}
;

and_constr[ConditionalElementDescr base]
@init {
AndDescr and = new AndDescr();
}
:
unary_constr[and]
( DOUBLE_AMPER
{
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_START);
}
unary_constr[and]
)*
{
if( and.getDescrs().size() == 1) {
$base.addOrMerge( (BaseDescr) and.getDescrs().get(0) );
} else if( and.getDescrs().size() > 1) {
$base.addDescr( and );
}
}
;

unary_constr[ConditionalElementDescr base]
:
( field_constraint[$base]
| LEFT_PAREN or_constr[$base] RIGHT_PAREN
| EVAL predicate[$base]
)
;

field_constraint[ConditionalElementDescr base]
@init {
FieldBindingDescr fbd = null;
FieldConstraintDescr fc = null;
RestrictionConnectiveDescr top = null;
}
:
(
ID ':'
{
fbd = new FieldBindingDescr();
fbd.setIdentifier( $ID.text );
fbd.setLocation( offset($ID.line), $ID.pos );
fbd.setStartCharacter( ((CommonToken)$ID).getStartIndex() );
$base.addDescr( fbd );

}

f=accessor_path
{
// use $f.start to get token matched in identifier
// or use $f.text to get text.
if( $f.text != null ) {
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR);
location.setProperty(Location.LOCATION_PROPERTY_PROPERTY_NAME, $f.text);

if ( fbd != null ) {
fbd.setFieldName( $f.text );
// may have been overwritten
fbd.setStartCharacter( ((CommonToken)$ID).getStartIndex() );
}
fc = new FieldConstraintDescr($f.text);
fc.setLocation( offset($f.start.getLine()), $f.start.getCharPositionInLine() );
fc.setStartCharacter( ((CommonToken)$f.start).getStartIndex() );
top = fc.getRestriction();

// it must be a field constraint, as it is not a binding
if( $ID == null ) {
$base.addDescr( fc );
}
}
}
(
or_restr_connective[top]
{
// we must add now as we didn't before
if( $ID != null) {
$base.addDescr( fc );
}
}
|
'->' predicate[$base]
)?
)
|
(
f=accessor_path
{
// use $f.start to get token matched in identifier
// or use $f.text to get text.
if( $f.text != null ) {
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR);
location.setProperty(Location.LOCATION_PROPERTY_PROPERTY_NAME, $f.text);

fc = new FieldConstraintDescr($f.text);
fc.setLocation( offset($f.start.getLine()), $f.start.getCharPositionInLine() );
fc.setStartCharacter( ((CommonToken)$f.start).getStartIndex() );
top = fc.getRestriction();

$base.addDescr( fc );
}
}
or_restr_connective[top]
)
;
catch[ NoViableAltException nvae ] {
if( input.LT(1) != null ) {
// in case of incomplete parsing, build as much as possible of the AST
// so that IDE requirements can be met
fc = new FieldConstraintDescr( input.LT(1).getText() );
fc.setLocation( offset(input.LT(1).getLine()), input.LT(1).getCharPositionInLine() );
fc.setStartCharacter( ((CommonToken)input.LT(1)).getStartIndex() );
$base.addDescr( fc );
}
throw nvae;
}


or_restr_connective[ RestrictionConnectiveDescr base ]
options {
backtrack=true;
}
@init {
RestrictionConnectiveDescr or = new RestrictionConnectiveDescr(RestrictionConnectiveDescr.OR);
}
:
and_restr_connective[or]
(
options {backtrack=true;} :
DOUBLE_PIPE
{
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR);
}
and_restr_connective[or]
)*
;
finally {
if( or.getRestrictions().size() == 1 ) {
$base.addOrMerge( (RestrictionDescr) or.getRestrictions().get( 0 ) );
} else if ( or.getRestrictions().size() > 1 ) {
$base.addRestriction( or );
}
}

and_restr_connective[ RestrictionConnectiveDescr base ]
@init {
RestrictionConnectiveDescr and = new RestrictionConnectiveDescr(RestrictionConnectiveDescr.AND);
}
:
constraint_expression[and]
( options {backtrack=true;}
: t=DOUBLE_AMPER
{
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR);
}
constraint_expression[and]
)*
;
finally {
if( and.getRestrictions().size() == 1) {
$base.addOrMerge( (RestrictionDescr) and.getRestrictions().get( 0 ) );
} else if ( and.getRestrictions().size() > 1 ) {
$base.addRestriction( and );
}
}

constraint_expression[RestrictionConnectiveDescr base]
:
( compound_operator[$base]
| simple_operator[$base]
| LEFT_PAREN
{
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR);
}
or_restr_connective[$base]
RIGHT_PAREN
)
;

simple_operator[RestrictionConnectiveDescr base]
@init {
String op = null;
String paramText = null;
boolean isNegated = false;
}
:
( t='=='
| t='>'
| t='>='
| t='<'
| t='<='
| t='!='
| t=CONTAINS
| n=NOT t=CONTAINS
| t=EXCLUDES
| t=MATCHES
| t=SOUNDSLIKE
| n=NOT t=MATCHES
| t=MEMBEROF
| n=NOT t=MEMBEROF
| TILDE t=ID param=square_chunk?
| n=NOT TILDE t=ID param=square_chunk?
)
{
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT);
location.setProperty(Location.LOCATION_PROPERTY_OPERATOR, $t.text);
op = $t.text;
isNegated = $n != null;
if( param != null ) {
paramText = safeSubstring( $param.text, 1, $param.text.length()-1 );
}
}
rd=expression_value[$base, op, isNegated, paramText]
;
finally {
if ( $rd.rd == null && op != null ) {
$base.addRestriction( new LiteralRestrictionDescr(op, false, null) );
}
}

compound_operator[RestrictionConnectiveDescr base]
@init {
String op = null;
RestrictionConnectiveDescr group = null;
}
:
( IN
{
op = "==";
group = new RestrictionConnectiveDescr(RestrictionConnectiveDescr.OR);
$base.addRestriction( group );
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT);
location.setProperty(Location.LOCATION_PROPERTY_OPERATOR, "in");
}
| NOT IN
{
op = "!=";
group = new RestrictionConnectiveDescr(RestrictionConnectiveDescr.AND);
$base.addRestriction( group );
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT);
location.setProperty(Location.LOCATION_PROPERTY_OPERATOR, "in");
}
)
LEFT_PAREN rd=expression_value[group, op, false, null]
( COMMA rd=expression_value[group, op, false, null] )*
RIGHT_PAREN
{
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_END);
}
;

expression_value[RestrictionConnectiveDescr base, String op, boolean isNegated, String paramText] returns [RestrictionDescr rd]
@init {
$rd = null;
}
:
( ap=accessor_path
{
if( $ap.text.indexOf( '.' ) > -1 || $ap.text.indexOf( '[' ) > -1) {
$rd = new QualifiedIdentifierRestrictionDescr($op, $isNegated, $paramText, $ap.text);
} else {
$rd = new VariableRestrictionDescr($op, $isNegated, $paramText, $ap.text);
}
}
| lc=literal_constraint
{
$rd = new LiteralRestrictionDescr($op, $isNegated, $paramText, $lc.text, $lc.type );
}
| rvc=paren_chunk
{
$rd = new ReturnValueRestrictionDescr($op, $isNegated, $paramText, safeSubstring( $rvc.text, 1, $rvc.text.length()-1) );
}
)
{
if( $rd != null ) {
$base.addRestriction( $rd );
}
location.setType(Location.LOCATION_LHS_INSIDE_CONDITION_END);
}
;

literal_constraint returns [String text, int type]
@init {
$text = null;
}
: ( t=STRING { $text = getString( $t.text ); $type = LiteralRestrictionDescr.TYPE_STRING; }
| t=INT { $text = $t.text; $type = LiteralRestrictionDescr.TYPE_NUMBER; }
| t=FLOAT { $text = $t.text; $type = LiteralRestrictionDescr.TYPE_NUMBER; }
| t=BOOL { $text = $t.text; $type = LiteralRestrictionDescr.TYPE_BOOLEAN; }
| t=NULL { $text = null; $type = LiteralRestrictionDescr.TYPE_NULL; }
)
;

predicate[ConditionalElementDescr base]
@init {
PredicateDescr d = null;
}
:
text=paren_chunk
{
if( $text.text != null ) {
d = new PredicateDescr( );
d.setContent( safeSubstring( $text.text, 1, $text.text.length()-1 ) );
d.setEndCharacter( ((CommonToken)$text.stop).getStopIndex() );
$base.addDescr( d );
}
}
;


curly_chunk
:
LEFT_CURLY ( ~(LEFT_CURLY|RIGHT_CURLY) | curly_chunk )* RIGHT_CURLY
;

paren_chunk
:
LEFT_PAREN ( ~(LEFT_PAREN|RIGHT_PAREN) | paren_chunk )* RIGHT_PAREN
;

square_chunk
:
LEFT_SQUARE ( ~(LEFT_SQUARE|RIGHT_SQUARE) | square_chunk )* RIGHT_SQUARE
;

qualified_id returns [ String text ]
@init {
StringBuffer buf = new StringBuffer();
}
@after {
$text = buf != null ? buf.toString() : "";
}
: ID {buf.append($ID.text);} ( DOT identifier {buf.append("."+$identifier.text);} )* ( LEFT_SQUARE RIGHT_SQUARE {buf.append("[]");})*
;

dotted_name returns [ String text ]
@init {
StringBuffer buf = new StringBuffer();
}
@after {
$text = buf != null ? buf.toString() : "";
}
: i=identifier {buf.append($i.text);} ( DOT i=identifier {buf.append("."+$i.text);} )* ( LEFT_SQUARE RIGHT_SQUARE {buf.append("[]");})*
;

accessor_path returns [ String text ]
@init {
StringBuffer buf = new StringBuffer();
}
@after {
$text = buf != null ? buf.toString() : "";
}
: a=accessor_element {buf.append($a.text);} ( DOT a=accessor_element {buf.append("."+$a.text);} )*
;

accessor_element returns [ String text ]
@init {
StringBuffer buf = new StringBuffer();
}
@after {
$text = buf != null ? buf.toString() : "";
}
:
i=identifier {buf.append($i.text);} (s=square_chunk {buf.append($s.text);} )*
;

rhs_chunk[RuleDescr rule]
:
THEN { location.setType( Location.LOCATION_RHS ); }
( ~END )*
loc=END opt_semicolon
{
// ignoring first line in the consequence
String buf = input.toString( $THEN, $loc );
// removing final END keyword
int idx=4;
while( idx < buf.length()-3 && (buf.charAt(idx) == ' ' || buf.charAt(idx) == '\t') ) {
idx++;
}
if( idx < buf.length()-3 && buf.charAt(idx) == '\r' ) idx++;
if( idx < buf.length()-3 && buf.charAt(idx) == '\n' ) idx++;
buf = safeSubstring( buf, idx, buf.length()-3 );
$rule.setConsequence( buf );
$rule.setConsequenceLocation(offset($THEN.line), $THEN.pos);
$rule.setEndCharacter( ((CommonToken)$loc).getStopIndex() );
location.setProperty( Location.LOCATION_RHS_CONTENT, $rule.getConsequence() );
}
;

name returns [String name]
: ID { $name = $ID.text; }
| STRING { $name = getString( $STRING.text ); }
;

identifier
: ID
| PACKAGE
| FUNCTION
| GLOBAL
| IMPORT
| EVENT
| RULE
| QUERY
| TEMPLATE
| ATTRIBUTES
| ENABLED
| SALIENCE
| DURATION
| DIALECT
| FROM
| INIT
| ACTION
| REVERSE
| RESULT
| WHEN
| THEN
| END
| IN
;

WS : ( ' '
| '\t'
| '\f'
| EOL
)+
{ $channel=HIDDEN; }
;

fragment
EOL :
( ( '\r\n' )=> '\r\n' // Evil DOS
| '\r' // Macintosh
| '\n' // Unix (the right way)
)
;

INT
: ('-')?('0'..'9')+
;

FLOAT
: ('-')?('0'..'9')+ '.' ('0'..'9')+
;

STRING
: ('"' ( EscapeSequence | ~('\\'|'"') )* '"')
| ('\'' ( EscapeSequence | ~('\\'|'\'') )* '\'')
;

fragment
HexDigit : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
EscapeSequence
: '\\' ('b'|'B'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\'|'.'|'o'|
'x'|'a'|'e'|'c'|'d'|'D'|'s'|'S'|'w'|'W'|'p'|'A'|
'G'|'Z'|'z'|'Q'|'E'|'*'|'['|']'|'('|')'|'$'|'^'|
'{'|'}'|'?'|'+'|'-'|'&'|'|')
| UnicodeEscape
| OctalEscape
;

fragment
OctalEscape
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
| '\\' ('0'..'7') ('0'..'7')
| '\\' ('0'..'7')
;

fragment
UnicodeEscape
: '\\' 'u' HexDigit HexDigit HexDigit HexDigit
;

BOOL
: ('true'|'false')
;

PACKAGE : 'package';

IMPORT : 'import';

FUNCTION : 'function';

EVENT : 'event';

GLOBAL : 'global';

RULE : 'rule';

QUERY : 'query';

TEMPLATE : 'template';

ATTRIBUTES : 'attributes';

DATE_EFFECTIVE
: 'date-effective';

DATE_EXPIRES
: 'date-expires';

ENABLED : 'enabled';

SALIENCE
: 'salience';

NO_LOOP : 'no-loop';

AUTO_FOCUS
: 'auto-focus';

ACTIVATION_GROUP
: 'activation-group';

AGENDA_GROUP
: 'agenda-group';

DIALECT
: 'dialect';

RULEFLOW_GROUP
: 'ruleflow-group';

DURATION
: 'duration';

LOCK_ON_ACTIVE
: 'lock-on-active';

FROM : 'from';

ACCUMULATE
: 'accumulate';

INIT : 'init';

ACTION : 'action';

REVERSE : 'reverse';

RESULT : 'result';

COLLECT : 'collect';

ENTRY_POINT : 'entry-point';

OR : 'or';

AND : 'and';

CONTAINS
: 'contains';

EXCLUDES
: 'excludes';

MEMBEROF
: 'memberOf';

MATCHES : 'matches';

SOUNDSLIKE : 'soundslike';

IN : 'in';

NULL : 'null';

EXISTS : 'exists';

NOT : 'not';

EVAL : 'eval';

FORALL : 'forall';

WHEN : 'when';

THEN : 'then';

END : 'end';

ID
: ('a'..'z'|'A'..'Z'|'_'|'$'|'\u00c0'..'\u00ff')('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'\u00c0'..'\u00ff')*
;

LEFT_PAREN
: '('
;

RIGHT_PAREN
: ')'
;

LEFT_SQUARE
: '['
;

RIGHT_SQUARE
: ']'
;

LEFT_CURLY
: '{'
;

RIGHT_CURLY
: '}'
;

COMMA : ','
;

DOT : '.'
;

DOUBLE_AMPER
: '&&'
;

DOUBLE_PIPE
: '||'
;

TILDE : '~';

SH_STYLE_SINGLE_LINE_COMMENT
: '#' ( options{greedy=false;} : .)* EOL /* ('\r')? '\n' */
{ $channel=HIDDEN; setText("//"+getText().substring(1));}
;


C_STYLE_SINGLE_LINE_COMMENT
: '//' ( options{greedy=false;} : .)* EOL // ('\r')? '\n'
{ $channel=HIDDEN; }
;

MULTI_LINE_COMMENT
: '/*' (options{greedy=false;} : .)* '*/'
{ $channel=HIDDEN; }
;

MISC :
'!' | '@' | '$' | '%' | '^' | '*' | '_' | '-' | '+' | '?' | '=' | '/' | '\'' | '\\' | '|' | '&'
;

Saturday, February 16, 2008

2008-02-16 Saturday

The evaluation of the Open Source WebLOAD-8.1 testing software continues - and so far I am still very pleased with its functionality and ease of use.


Results of the POVRay Short Code Contest #5 - The animation round. Some VERY cool animations.

I would like to spend some time looking into this tool: Persistence of Vision Raytracer.
The Persistence of Vision Raytracer is a high-quality, totally free tool for creating stunning three-dimensional graphics. It is available in official versions for Windows, Mac OS/Mac OS X and i86 Linux.


Ray Kurzweil: Machines 'to match man by 2029'

CHALLENGES FACING HUMANITY
Make solar energy affordable
Provide energy from fusion
Develop carbon sequestration
Manage the nitrogen cycle
Provide access to clean water
Reverse engineer the brain
Prevent nuclear terror
Secure cyberspace
Enhance virtual reality
Improve urban infrastructure
Advance health informatics
Engineer better medicines
Advance personalised learning
Explore natural frontiers

The 14 challenges were announced at the annual meeting of the American Association for the Advancement of Science in Boston


Virus from China the gift that keeps on giving...digital photo frames virus (Trojan)

Use of Rogue DNS Servers on Rise

Friday, February 08, 2008

2008-02-08 Friday

What an incredibly busy week.

I've reviewed the book contract the pubisher emailed me - and have agreed to the terms they offered. A signed copy is on the way. Target delivery for the finished draft will be end of June.

I had an interesting inquiry from a possible client this week - I've asked my former colleagues at Assessments.com to collaborate on providing a solution. Seven years after I designed their original application architecture - the core components of their authoring, publishing, scoring, and reporting engines are still largely based on my original design and code. The flexibility of the design, based on very configurable meta-data rules, has stood the test of time very well.

This year I plan to expand my consulting practice by hiring additional staff and winning more client engagements.

I'm developing a SOA Dashboard application for a client that will generate some very useful SOA metrics based on harvesting certain governance messages and service health events from a core logging service framework. These messages will subsequently be processed and a summary report generated on a rolling basis. I'm planning on incorporating Graphviz to generate some very cool diagrams for the dashboard. This will be released on Sourceforge.net under the PNW SOA COMMONS (pnwsoacommons) project.




PushToTest

Over the last week, I've been assisting a client's Test Team with evaluating the capabilities of the PushToTest tool.

The 5.0 release I installed had problems replaying a very basic test scenario script that replayed fine under Firefox (using the TestGen4Web plugin).

Apparently, the 5.1 RC1 Release Notes indicate that there was a known problem with replaying scripts that worked fine under TestGen4Web:
"TestMaker 5.1 changes the way TestGen4Web scripts are run in the TestNode environment. The new script runner uses TestGen4Web's htmlunit-interpreter package. This improves TestMaker's ability to natively run TestGen4Web recorded unit tests."

In my experience, PushToTest 5.1 RC1 ***STILL*** has a problem replaying scripts that work perfectly under TestGen4Web (!!!)

After spending a few days attempting to resolve the problem - and facing mounting pressure from some stakeholders within the client organization - I had to find an alternative.





WebLOAD.org

I installed WebLOAD-8.1.0.141 - spent about 5 mintues going through one of their video tutorials - and was able to successfully run a load test against the target application.

If you try to use the webload.org download link to sourceforge.net - it will hang for some reason - but you can go directly to sourceforge.net and simply do a search for "WebLOAD".

Conclusions
I have to say I am VERY IMPRESSED with the quality of the WebLOAD application, documentation, and tutorials. PushToTest seems to me to still be a viable tool, and I will keep an eye on its future development.





Some Links
Hostile ta Vista, Baby

Is Linus Torvalds even speaking for Linux anymore?

WSO2: release candidate of Web Services Framework for Spring

Jawr: javascript bundling and compression for java applications

The future of XML

Antivirus Inventor: Security Departments Are Wasting Their Time