Wednesday, March 25, 2009

Cruisecontrol usage

Cruisecontrol dashboard can be accessed at the location: http://10.177.135.55:8080/dashboard/tab/dashboard
A reference for creating the config.xml file, which you will need soon, is present at this location:http://cruisecontrol.sourceforge.net/main/configxml.html

You can add a project for automated builds into CC by doing the following steps:

1. Add a project tag to the C:\CruiseControl\config.xml file. There are two types of builds that you may configure:
2a. Build that takes place within a certain interval i.e. hourly build. This usually checks that code checked in by various developers are compiling.
2b. Build that takes place once everyday at the night. This usually checks that the code in the source control compiles and deploys on the appserver. You may run the tests too in this build and build the project site which maven does very well.
2. Checkout the project in the C:\CruiseControl\projects folder of that machine. Yes, you need to manually check out the project in the projects folder for the first time. Later, CC does the updates. But, first, check #3.
3. It is a good idea to have two folders like this: C:\CruiseControl\projects\hourly and C:\CruiseControl\projects\nightly in which you check out the projects.
4. For the project tag of the type in 2a use the following template(The string between ##, including the hashes, is to be replaced with the suitable string):
<project name="#project-name#">
<listeners>
<currentbuildstatuslistener file="logs/#project-name#/status.txt"/>
</listeners>

<bootstrappers>
<!-- This is a sample for subversion source control. This command is different for different source controls. Add as many paths as you want updated.-->
<svnbootstrapper localWorkingCopy="projects/hourly/#the path to the checked out project where svn update needs to take place#" username="#username#" password="#password#"/>
</bootstrappers>

<!--This tag is to specify the paths that you want CC to track changes made in. i.e. If there is any change of a file in these paths a build will be triggered.-->
<modificationset quietperiod="30" >
<!--Again, this is for subversion source control. Add as many paths as you want to track.-->
<svn localWorkingCopy="projects/hourly/#the path to the checked out project where you want CC to detect changes for a build to take place#" username="#username#" password="#password#"/>
</modificationset>

<!--This tag species that changes must be checked every one hour. If changes are detected, then the commands specified must be run, here it is a maven command.-->
<schedule interval="3600">
<!--The maven command to run if a build must take place. This could be an ant command too. Check the CC reference for the right syntax.-->
<maven2 mvnhome="${mvn.home}" pomfile="projects/hourly/#the path to the build file in the checked out project.#" goal="clean install" flags="-e"/>
</schedule>

<publishers>
<currentbuildstatuspublisher file="logs/#project-name#/status.txt"/>
<email mailhost="mail.oracle.com" returnaddress="#build-manager#@oracle.com" buildresultsurl="http://10.177.135.55:8080/buildresults/#project-name#" reportsuccess="never">
<failure address="#dev-team-email-id(s)#@oracle.com"/>

</email>
</publishers>
</project>

5. For the project tag of the type in 2b use the following template(The string between ##, including the hashes, is to be replaced with the suitable string):
<project name="#project-name#">
<listeners>
<currentbuildstatuslistener file="logs/#project-name#/status.txt"/>
</listeners>

<bootstrappers>
<!-- This is a sample for subversion source control. This command is different for different source controls. Add as many paths as you want updated.-->
<svnbootstrapper localWorkingCopy="projects/hourly/#the path to the checked out project where svn update needs to take place#" username="#username#" password="#password#"/>
</bootstrappers>

<!--This tag is to specify the paths that you want CC to track changes made in. i.e. If there is any change of a file in these paths a build will be triggered.-->
<modificationset>
<!--Again, this is for subversion source control. Add as many paths as you want to track.-->
<svn localWorkingCopy="projects/nightly/#the path to the checked out project where you want CC to detect changes for a build to take place#" username="#username#" password="#password#"/>
</modificationset>

<!--This tag species that there is no schedule. So, the time to build is taken from the command. Here, it is 8pm everyday.-->
<schedule>
<!--The maven command to run if a build must take place. This could be an ant command too. Check the CC reference for the right syntax.-->
<maven2 mvnhome="${mvn.home}" time="2000" pomfile="projects/nightly/#the path to the build file in the checked out project.#" goal="clean install" flags="-e"/>
</schedule>

<publishers>
<currentbuildstatuspublisher file="logs/#project-name#/status.txt"/>
<email mailhost="mail.oracle.com" returnaddress="#build-manager#@oracle.com" buildresultsurl="http://10.177.135.55:8080/buildresults/#project-name#" reportsuccess="never">
<failure address="#dev-team-email-id(s)#@oracle.com"/>

</email>
</publishers>
</project>
6. After this step one can go to the CC dashboard and monitor the project builds as well as trigger builds manually.

Wednesday, March 18, 2009

Oracle Coherence learnings, so far...Part 2

1 . If you want to listen to events like when a new object is inserted in the coherence cache(CC) or when an object is deleted from CC or when an object in CC is updated do it like this folks:
NamedCache cache = CacheFactory.getCache("person");
cache.addMapListener(new MapListener() {

public void entryInserted(MapEvent mapEvent) {
//Code when some new object is inserted into cache
}

public void entryUpdated(MapEvent mapEvent) {
Object key = mapEvent.getKey();
Object oldVal = mapEvent.getOldValue();
Object val = mapEvent.getNewValue();
System.out.println("Old value:"+oldVal+", New value being added:"+val);
}

public void entryDeleted(MapEvent mapEvent) {
//Code when some an object is deleted into cache
}
});


2. Up until now we have just done put and get of data into the cache. I am sure, by now, someone is craving to ask what about concurrency. If we want to control concurrency to the data we have the option to lock and unlock keys. But there is a better way to do this: Entry Processes are agents that perform processing against entries, and will carry this out directly where the data is being held. The sort of processing you can carry out may change the data, e.g. create, update or remove or may just perform calculations on the data. Entry processors that work against the same key will be logically queued. This means that you can achieve lock-free (high performance) processing. This is called in-line processing of data. Custom entry processes may be written in the following way:
Class RaiseSalary extents AbstractProcessor {
...
public Object process (Entry entry) {
Employee emp = (Employee)entry.getValue();
emp.setSalary(emp.getSalary() * 1.10);
entry.setValue(emp);
return null;
}

To invoke this you then do the following:
empCache.invokeAll(AlwaysFilter.INSTANCE, new RaiseSalary());

3. Up until now, we've seen simple keys. What if when we want to have a composite key like the id and the version number. Then it is a good idea to wrap all the member elements that form a composite key into an inner class and call it "public static class Key implements ExternalizableLite". A sample key implementation may look like this:
public static class Key implements ExternalizableLite {

// lets define a key of id and version
private int id;
private int version;

public Key() {
//for serializble
}

public Key(int id, int version) {
this.id = id;
this.version = version;
}

public Key(Person p) {
this.id = p.getId();
this.version = 1; // default to version 1
}

public void writeExternal(DataOutput dataOutput) throws IOException {
ExternalizableHelper.writeInt(dataOutput, this.id);
ExternalizableHelper.writeInt(dataOutput, this.version);
}

public void readExternal(DataInput dataInput) throws IOException {
this.id = ExternalizableHelper.readInt(dataInput);
this.version = ExternalizableHelper.readInt(dataInput);
}

@Override
public boolean equals(Object object) {
...
}

@Override
public int hashCode() {
final int PRIME = 37;
int result = 1;
return result;
}
}

As a next step, we can target for efficiencies of partitioning. That is, in the cluster of caches, we can target for similar objects to be in the same cache instance. For this the inner class can implement KeyAssociation and override the method getAssociatedKey(). With this, for instance, if this method returns the same surname then those persons are placed in the same cache instance.

Oracle Coherence learnings, so far...Part 1

I've been going thru a lab which is dealing with a set of new functions in each chapter. Here are my learnings so far:

1.Definition: Oracle Coherence is an in-memory data grid solution that enables organizations to predictably scale mission-critical applications by providing fast access to frequently used data.

2. The standard way of putting and getting data into cache:
NamedCache cache = CacheFactory.getCache("person");
Person p1 = new Person(2, "Jade", "Goody", "London, 38", 36, Person.FEMALE);
cache.put(p1.getId(), p1);
Person p2 = (Person)cache.get(1);


3. The custom objects that you put into coherence cache must be atleast Serializable. If you want a more efficient way then implement com.tangosol.io.ExternalizableLite. This will require you to implement two methods too but mashalling and unmarshalling of objects become very efficient.

4. To do bulk upload of data into the in-memory cache, you would want to do it efficiently like this:
public static void bulkLoad(NamedCache cache, Connection conn)
{
Statement s;
ResultSet rs;
Map buffer = new HashMap();

try
{
int count = 0;
s = conn.createStatement();
rs = s.executeQuery("select key, value from table");
while (rs.next())
{
Integer key = new Integer(rs.getInt(1));
String value = rs.getString(2);
buffer.put(key, value);

// this loads 1000 items at a time into the cache
if ((count++ % 1000) == 0)
{
cache.putAll(buffer);
buffer.clear();
}
}
if (!buffer.isEmpty())
{
cache.putAll(buffer);
}
...
}
catch (SQLException e)
{...}

}
5. To carry-out efficient processing of filtered results you may want to do this instead of the regular iterator stuff:
public static void performQuery()
{
NamedCache c = CacheFactory.getCache("test");

// Search for entries that start with 'c'
Filter query = new LikeFilter(IdentityExtractor.INSTANCE, "c%", '\\', true);

// Perform query, return keys of entries that match
Set keys = c.keySet(query);

// The amount of objects to process at a time
final int BUFFER_SIZE = 100;

// Object buffer
Set buffer = new HashSet(BUFFER_SIZE);

for (Iterator i = keys.iterator(); i.hasNext();)
{
buffer.add(i.next());

if (buffer.size() >= BUFFER_SIZE)
{
// Bulk load BUFFER_SIZE number of objects from cache
Map entries = c.getAll(buffer);

// Process each entry
process(entries);

// Done processing these keys, clear buffer
buffer.clear();
}
}
// Handle the last partial chunk (if any)
if (!buffer.isEmpty())
{
process(c.getAll(buffer));
}

}
6. This is how filtering works:
Set malesOver35 = cache.entrySet(
new AndFilter(new EqualsFilter("getGender", Person.MALE),
new GreaterEqualsFilter("getAge", 35)));

7. This is how aggregation works:
Double avgAgeMales =
(Double)cache.aggregate(new EqualsFilter("getGender", Person.MALE),
new DoubleAverage("getAge"));


8. Entry Processes are agents that perform processing against entries, and will carry this out directly where the data is being held. The sort of processing you can carry out may change the data, e.g. create, update or remove or may just perform calculations on the data. Entry processors that work against the same key will be logically queued. This means that you can achieve lock-free (high performance) processing. A small example is as follows:
Class RaiseSalary extents AbstractProcessor {
...
public Object process (Entry entry) {
Employee emp = (Employee)entry.getValue();
emp.setSalary(emp.getSalary() * 1.10);
entry.setValue(emp);
return null;
}
To invoke this you then do the following:
empCache.invokeAll(AlwaysFilter.INSTANCE, new RaiseSalary());