Tuesday, November 6, 2012

How to Organize Developer Folder Structure

Requirement:
Easy to access Folder Structure on Developer PC.

Solution:
Create it! :)
I've meet the problem when I try to organize folder structure on my PC. 
So my needs from a developer point of view are:
  • Easy to access
  • Simple path
  • Non white spaces in path
  • Arrange projects by clients
  • Arrange documents by clients
  • Group installed software
  • Workspace for each client
My solution looks like:
 

And Windows batch file for creating this structure:
@echo off set CURRENT_DIR=D: echo Selected folder: %CURRENT_DIR% md %CURRENT_DIR%\docs\work\clients md %CURRENT_DIR%\docs\personal md %CURRENT_DIR%\docs\books\java md %CURRENT_DIR%\docs\books\linux md %CURRENT_DIR%\docs\books\documentum md %CURRENT_DIR%\projects\personal md %CURRENT_DIR%\projects\work\clients md %CURRENT_DIR%\workspace\work\clients md %CURRENT_DIR%\workspace\personal md %CURRENT_DIR%\install md %CURRENT_DIR%\installed\java md %CURRENT_DIR%\installed\eclipse md %CURRENT_DIR%\installed\apache\maven md %CURRENT_DIR%\installed\apache\ant md %CURRENT_DIR%\installed\apache\tomcat md %CURRENT_DIR%\installed\apache\httpd md %CURRENT_DIR%\media\music md %CURRENT_DIR%\media\pictures md %CURRENT_DIR%\media\videos\movies
What about your folder structure %username% ? 
Fell free to show it ;)

Wednesday, October 3, 2012

Runtime deploy Java Webapp

Requirement:
Do not spend time for deploying Java web application.

Solution:
Use Jetty
Jetty is an HTTP server, HTTP client, and javax.servlet container.

So let's say we have the spring RESTful web application developing in Eclipse. Te structure of application is:

Inline image 2

The web application folder to deploy is /webapp, also is needed to add conf.properties and log4j.properties to the application classpath.
If you have noticed in src folder there is a package http.server here lies our savior. The class Launcher.java is the http server. In that class we have some code lines, let's look inside this class:

public class Launcher {
      public static void main(String[] args) throws Exception {
            Server server = new Server();

            Connector connector = new SelectChannelConnector();
            connector.setPort(8080);
            server.addConnector(connector);

            WebAppContext root = new WebAppContext("webapp""/");
            //Add .properties files to classpath
            WebAppClassLoader classLoader = new WebAppClassLoader(root);
            classLoader.addClassPath("conf/localhost");
            root.setClassLoader(classLoader);
            server.setHandlers(new Handler[] { root });
            server.start();
      }
}

For resolve all dependencies you need to download the following jars: 


That's all :) 
Also if your classes aren't compiled in webapp/WEB-INF/classes path then you can add them for example in that way:
classLoader.addClassPath("bin");

After running that class, go to your browser and open the address: http://localhost:8080/<servlet_path>
In my case the address is http://localhost:8080/service/xml/info and in the browser I get the:

Inline image 3

Happy developing!

Wednesday, July 18, 2012

Launch DqMan with predefined Environment configuration

"Life is very short to modify dmcl.ini manually"
Me.
Requirement:
Launch DqMan for specific docbase environment without edit dmcl.ini file.


Solution:
I've noticed that I spend much time for editing dmcl.ini file and launch again the DqMan for switching between environments. So the old my friend "cmd" came to help the issue. 
For that before launching DqMan I'm going to edit programatically dmc.ini and then start the dqman.exe. 
How I've done that? Bellow is showed:

1) I've create a batch file "confdqman.bat" with te following lines code:

@echo off

SET ENV=%1
SET ENV_ADRESS=%2
SET CONF_FILE="C:\Program Files\dqMan\dmcl.ini"
SET CONF_FOOTER=.\footer.txt
SET CONF_HEADER=.\header.txt
SET DQMAN_PATH="C:\Program Files\dqMan\"


:start
rem If the dmc.ini does not exist go to nonexistconffile label
if not exist %CONF_FILE% goto nonexistconffile

rem Copy all content of header.txt to dmc.ini file, the command means that file will be cleared before writing
findstr /x /r /c:.* %CONF_HEADER% > %CONF_FILE%

rem append a env comment ex: #DEV to dmc.ini
echo #%ENV% >> %CONF_FILE%

rem append the host name to dmc.ini
echo host = %ENV_ADRESS% >> %CONF_FILE%

rem append all content of footer.txt to dmc.ini file
findstr /x /r /c:.* %CONF_FOOTER% >> %CONF_FILE%

rem go to DqMan installed path
cd %DQMAN_PATH%

rem run DqMan
start "" dqman.exe

rem go to endproc label
goto endproc

:nonexistconffile
echo Non exist %CONF_FILE%
echo Make shure the file exist then press Enter
pause
goto start
:endproc

Here the  ENV=%1 and ENV_ADRESS=%2  these variables are filled from called parameters respectivly %1 - first parameter and %2 - second parameter.

2) If you have noticed there are two adition files .\footer.txt and .\header.txt these files serve for generating the dmcl.ini content. 
For my environements the content of these files are: 
.\header.txt : 

# Default DMCL.INI. Refer to DMCLFULL.INI for other options
# Assuming No Network File System
# Assuming No Compression for Content Tunneling
[DOCBROKER_PRIMARY]


.\footer.txt :

[DMAPI_CONFIGURATION]
cache_queries = T
token_storage_enabled=F
token_storage_path=d:\Documentum\apptoken
client_codepage=UTF-8
client_os_codepage=UTF-8
max_session_count=1000
connect_pooling_enabled=T



3) Then for each environment I've create addition batch file that call "confdqman.bat" with predefined parameters. 
For example for DEV environment I've create in the same folder "dev-dqman.bat" batch file with these lines:

@echo off
rem %1=DEV , %2=192.168.10.12

call  %0\..\confdqman.bat DEV 192.168.10.12

That's all, now, the moment of truth!!!
After double click on dev-dqman.bat file DqMan has been launched and "Voila" it suggest to connect to DEV docbase.
Now, if I open C:\Program Files\dqMan\dmcl.ini config file I can see the configuration:

# Default DMCL.INI. Refer to DMCLFULL.INI for other options
# Assuming No Network File System
# Assuming No Compression for Content Tunneling
[DOCBROKER_PRIMARY]
#DEV
host = 192.168.10.12

[DMAPI_CONFIGURATION]
cache_queries = T
token_storage_enabled=F
token_storage_path=d:\Documentum\apptoken
client_codepage=UTF-8
client_os_codepage=UTF-8
max_session_count=1000

After configuring all environments all batch files are:

Inline image 1

After creating shortcuts on Desktop and change the icons :))

Inline image 2

Nice, isn't it?

Thursday, March 29, 2012

Ant task for update the jar files in Documentum


“You do not really understand something unless you can explain it to your grandmother”
Albert Einstein.


This quote pushed me to start this blog. Why I'm writing the blog in English? The answer is quite simple, to improve my English :)
These articles will include two points Requirement (the issue) and Solution (how to solve the issue). So let's begin.


Requirement:
Update the jar files in Documentum repository immediately after it is created.


Solution:
We all know that for update a documentum module TBO, SBO it is enough just to checkout - checkin the jar file inside the module folder, yes there are a lot of mode to do that: DA, WebTop, Composer (that usually fails), ... but the requirement is to update it automatically in repository after it is created. I have decide to put this procedure immediately after the jar is created, of course in Ant task.
The Ant task in build.xml will look like that:

<!-- Update jarfiles in docbase -->
              <checkoutcheckin>
                     <docbaseobject jarfile=".dist/ex_interfaces.jar" jarobject="ex_interfaces.jar" />
                     <docbaseobject jarfile="./dist/ex_impl.jar" jarobject="ex_impl.jar" />
              </checkoutcheckin>

It looks very nice isn’t it?
First of all we need to declare Ant custom CheckOutCheckIn class extends Task class which will do the given job.

public class CheckOutCheckIn extends Task {
      
@Override
       public void execute() throws BuildException {
              // TODO Auto-generated method stub
              super.execute();
       }
}

Yes, you have notice correctly, the execute() method is the method which shall do the job. Our execute() method will be quite simple:

@Override
       public void execute() throws BuildException {
              String classPath = System.getProperties().getProperty("java.class.path", null);
              log("Class Path: " + classPath);
              try {
                     initSession();
                     doCheckout();
                     doCheckin();
              } catch (DfException e) {
                     throw new BuildException(e);
              } catch (Exception e) {
                     throw new BuildException(e);
              } finally {
                     releaseSession();
              }
       }

That’s not enough, we need a way to map the jar files and the docbase object. For that I have create an inner bean class which will contain a jarFile/object pair inside.

       public static class DocBaseObject extends Task {
              private String jarfile;
              private String jarobject;

              public DocBaseObject() {
              }

              public DocBaseObject(String file, String object) {
                     jarfile = file;
                     jarobject = object;
              }

              public String getJarfile() {
                     return jarfile;
              }

              public void setJarfile(String localfile) {
                     this.jarfile = localfile;
              }

              public String getJarobject() {
                     return jarobject;
              }

              public void setJarobject(String docbaseObject) {
                     this.jarobject = docbaseObject;
              }

       }

This class also extends Ant Task class because we will use it like inner parameter to the main Ant task. So our class now looks like this:

public class CheckOutCheckIn extends Task {
      
@Override
       public void execute() throws BuildException {
              String classPath = System.getProperties().getProperty("java.class.path", null);
              log("Class Path: " + classPath);
              try {
                     initSession();
                     doCheckout();
                     doCheckin();
              } catch (DfException e) {
                     throw new BuildException(e);
              } catch (Exception e) {
                     throw new BuildException(e);
              } finally {
                     releaseSession();
              }
       }

       public static class DocBaseObject extends Task {
              private String jarfile;
              private String jarobject;

              public DocBaseObject() {
              }

              public DocBaseObject(String file, String object) {
                     jarfile = file;
                     jarobject = object;
              }

              public String getJarfile() {
                     return jarfile;
              }

              public void setJarfile(String localfile) {
                     this.jarfile = localfile;
              }

              public String getJarobject() {
                     return jarobject;
              }

              public void setJarobject(String docbaseObject) {
                     this.jarobject = docbaseObject;
              }

       }

}
It remains only to add implementation to all methods. Let’s start with inititSession() method:

              private void initSession() throws Exception {
              URL urlPath = null;
              //getting ClassLoader for load dfc.properties
              ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
              if (classLoader != null) {
                     urlPath = classLoader.getResource("dfc.properties");
              }
              if (urlPath == null) {
                     urlPath = CheckOutCheckIn.class.getResource("dfc.properties");
              }
              if (urlPath == null) {
                     urlPath = CheckOutCheckIn.class.getClassLoader().getResource("dfc.properties");
              }
              log("dfc.properties path:" + urlPath.getPath());
             
              //set the dfc.properties.file parameter
              System.setProperty("dfc.properties.file", urlPath.getPath());
             
              //get config.properties file for initiate user name, password and docbase name
              ResourceBundle ownerBundle = ResourceBundle.getBundle("config");
              String docbaseName = ownerBundle.getString("docbase");
              String userName = ownerBundle.getString("username");
              String password = ownerBundle.getString("password");
              log("Creating session manager docbase: " + docbaseName + " ...");
              sMgr = createSessionManager(docbaseName, userName, password);
              log("Getting session from docbase " + docbaseName + " (might take some seconds) ...");
              session = sMgr.getSession(docbaseName);
              log("Session oppened.");
       }

The files config.properties and dfc.properties should be in class path, this can be done when the Ant task is declared in build.xml.

       <taskdef name="checkoutcheckin" classname="com.example.ant.CheckOutCheckIn">
              <classpath>
                     <pathelement location="${proj.location}/config/${build.env}" />
                     <pathelement location="${proj.location}/dist/checkoutcheckin.jar" />
              </classpath>
       </taskdef>

The parameter ${build.env} can has the values (dev,test …) like you can see below.
Folder structure in Project:

















The content of property file config.properties might be something like that:

docbase=DEV
username=dmadmin
password=dmadmin

The content of dfc.properties file I think is not necessary to show. :)
I have chosen this method to set environment because in our project there are already these folders.
Let’s go back to class, we have to add implementation to all methods. Next method is called doCheckout():

       private void doCheckout() throws DfException {
              log("Checkout start ...");
              IDfClientX clientx = new DfClientX();
              IDfCheckoutOperation operation = clientx.getCheckoutOperation();
              //iterate over all <docbaseobject> inner elements from Ant task
              for (DocBaseObject docbaseObj : docbaseobjects) {
                     IDfSysObject sysObj = (IDfSysObject) session.getObjectByQualification("dmc_jar where object_name='" + docbaseObj.getJarobject() + "'");
                     if (sysObj == null) {
                           log("Object: " + docbaseObj.getJarobject() + " can not be found.");
                           continue;
                     }
                     if (sysObj.isCheckedOut() == true) {
                           log("Object: " + docbaseObj.getJarobject() + " is already checked out.");
                           continue;
                     }
                     operation.add(sysObj);
                     log("Object: " + docbaseObj.getJarobject() + " added to Checkout Operation.");
              }
              executeOperation(operation);
              log("Checkout end.");
       }

       private void executeOperation(IDfOperation operation) throws DfException {
              boolean executeFlag = operation.execute();
              //if the operation fails then log all errors
              if (!executeFlag) {
                     IDfList errorList = operation.getErrors();
                     String message = "";
                     IDfOperationError error = null;

                     for (int i = 0; i < errorList.getCount(); i++) {
                           error = (IDfOperationError) errorList.get(i);
                           message += error.getMessage();
                     }
                     log("Errors:" + message);
              } else {
                     log("Checkout Operation ends successful");
              }
       }

I choose IDfCheckoutOperation to checkout all the objects simultaneously. But for doCheckin() operation I do not choose this way because the jar files might be in different folders. So the doCheckin() method is:

       private void doCheckin() throws DfException {
              log("Checkin start ...");
              //iterate over all <docbaseobject> inner elements
              for (DocBaseObject docbaseObj : docbaseobjects) {
                     IDfSysObject sysObj = (IDfSysObject) session.getObjectByQualification("dmc_jar where object_name='" + docbaseObj.getJarobject() + "'");
                     if (sysObj == null) {
                           log("Object: " + docbaseObj.getJarobject() + " can not be found.");
                           continue;
                     }
                     if (sysObj.isCheckedOut() == false) {
                           log("Object: " + docbaseObj.getJarobject() + " is not checked out.");
                           continue;
                     }
                     sysObj.setFile(docbaseObj.getJarfile());
                     sysObj.checkin(false, "CURRENT");
                     log("Object: " + docbaseObj.getJarobject() + ", file: " + docbaseObj.getJarfile() + " checked in.");
              }
              log("Checkin end.");
       }

Finally the class will be:

package com.example.ant;

import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Vector;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

import com.documentum.com.DfClientX;
import com.documentum.com.IDfClientX;
import com.documentum.fc.client.IDfClient;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.IDfList;
import com.documentum.fc.common.IDfLoginInfo;
import com.documentum.operations.IDfCheckoutOperation;
import com.documentum.operations.IDfOperation;
import com.documentum.operations.IDfOperationError;

public class CheckOutCheckIn extends Task {

       private List<DocBaseObject> docbaseobjects = new Vector<DocBaseObject>();
       public static IDfSessionManager sMgr = null;
       public static IDfSession session = null;

       public void addDocbaseobject(DocBaseObject docbaseobject) {
              docbaseobjects.add(docbaseobject);
       }

       @Override
       public void execute() throws BuildException {
              String classPath = System.getProperties().getProperty("java.class.path", null);
              log("Class Path: " + classPath);
              try {
                     initSession();
                     doCheckout();
                     doCheckin();
              } catch (DfException e) {
                     throw new BuildException(e);
              } catch (Exception e) {
                     throw new BuildException(e);
              } finally {
                     releaseSession();
              }
       }

       private void initSession() throws Exception {
              URL urlPath = null;
              //getting ClassLoader for load dfc.properties
              ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
              if (classLoader != null) {
                     urlPath = classLoader.getResource("dfc.properties");
              }
              if (urlPath == null) {
                     urlPath = CheckOutCheckIn.class.getResource("dfc.properties");
              }
              if (urlPath == null) {
                     urlPath = CheckOutCheckIn.class.getClassLoader().getResource("dfc.properties");
              }
              log("dfc.properties path:" + urlPath.getPath());

              //set the dfc.properties.file parameter
              System.setProperty("dfc.properties.file", urlPath.getPath());

              //get config.properties file for initiate user name, password and docbase name
              ResourceBundle ownerBundle = ResourceBundle.getBundle("config");
              String docbaseName = ownerBundle.getString("docbase");
              String userName = ownerBundle.getString("username");
              String password = ownerBundle.getString("password");
              log("Creating session manager docbase: " + docbaseName + " ...");
              sMgr = createSessionManager(docbaseName, userName, password);
              log("Getting session from docbase " + docbaseName + " (might take some seconds) ...");
              session = sMgr.getSession(docbaseName);
              log("Session oppened.");
       }

       private void releaseSession() {
              sMgr.release(session);
              log("Session closed.");
       }

       private IDfSessionManager createSessionManager(String docbase, String user, String pass) throws Exception {
              IDfClientX clientx = new DfClientX();
              IDfClient client = clientx.getLocalClient();
              IDfSessionManager sMgr = client.newSessionManager();
              IDfLoginInfo loginInfoObj = clientx.getLoginInfo();
              loginInfoObj.setUser(user);
              loginInfoObj.setPassword(pass);
              loginInfoObj.setDomain(null);
              sMgr.setIdentity(docbase, loginInfoObj);
              return sMgr;
       }

       private void doCheckout() throws DfException {
              log("Checkout start ...");
              IDfClientX clientx = new DfClientX();
              IDfCheckoutOperation operation = clientx.getCheckoutOperation();
              //iterate over all <docbaseobject> inner elements
              for (DocBaseObject docbaseObj : docbaseobjects) {
                     IDfSysObject sysObj = (IDfSysObject) session.getObjectByQualification("dmc_jar where object_name='" + docbaseObj.getJarobject() + "'");
                     if (sysObj == null) {
                           log("Object: " + docbaseObj.getJarobject() + " can not be found.");
                           continue;
                     }
                     if (sysObj.isCheckedOut() == true) {
                           log("Object: " + docbaseObj.getJarobject() + " is already checked out.");
                           continue;
                     }
                     operation.add(sysObj);
                     log("Object: " + docbaseObj.getJarobject() + " added to Checkout Operation.");
              }
              executeOperation(operation);
              log("Checkout end.");
       }

       private void executeOperation(IDfOperation operation) throws DfException {
              boolean executeFlag = operation.execute();
              //if the operation fails then log all errors
              if (!executeFlag) {
                     IDfList errorList = operation.getErrors();
                     String message = "";
                     IDfOperationError error = null;

                     for (int i = 0; i < errorList.getCount(); i++) {
                           error = (IDfOperationError) errorList.get(i);
                           message += error.getMessage();
                     }
                     log("Errors:" + message);
              } else {
                     log("Checkout Operation ends successful");
              }
       }

       private void doCheckin() throws DfException {
              log("Checkin start ...");
              //iterate over all <docbaseobject> inner elements
              for (DocBaseObject docbaseObj : docbaseobjects) {
                     IDfSysObject sysObj = (IDfSysObject) session.getObjectByQualification("dmc_jar where object_name='" + docbaseObj.getJarobject() + "'");
                     if (sysObj == null) {
                           log("Object: " + docbaseObj.getJarobject() + " can not be found.");
                           continue;
                     }
                     if (sysObj.isCheckedOut() == false) {
                           log("Object: " + docbaseObj.getJarobject() + " is not checked out.");
                           continue;
                     }
                     sysObj.setFile(docbaseObj.getJarfile());
                     sysObj.checkin(false, "CURRENT");
                     log("Object: " + docbaseObj.getJarobject() + ", file: " + docbaseObj.getJarfile() + " checked in.");
              }
              log("Checkin end.");
       }

       public static class DocBaseObject extends Task {
              private String jarfile;
              private String jarobject;

              public DocBaseObject() {
              }

              public DocBaseObject(String file, String object) {
                     jarfile = file;
                     jarobject = object;
              }

              public String getJarfile() {
                     return jarfile;
              }

              public void setJarfile(String localfile) {
                     this.jarfile = localfile;
              }

              public String getJarobject() {
                     return jarobject;
              }

              public void setJarobject(String docbaseObject) {
                     this.jarobject = docbaseObject;
              }

       }
}

The last thing we should do is to package this in jar file “checkoutcheckin.jar” to declare the task in build.xml and “voila” the job is done. ;)
Here an example how I use it.

<!-- DFC classpath -->
       <path id="dfc.classpath">
              <pathelement location="${dfc.path}/dfc.jar" />
             
              …
       </path>

Class com.saipem.dams.ant.CheckOutCheckIn is using DFC classes, so we need to add dfc classes to classpath too.

<!—Checkin checkout task definition-->
       <taskdef name="checkoutcheckin" classname="com.saipem.dams.ant.CheckOutCheckIn">
              <classpath>
                     <pathelement location="${dams_web.location}/config/${build.env}" />
                     <pathelement location="${dams_tools.location}/dist/checkoutcheckin.jar" />
              </classpath>
<classpath refid="dfc.classpath" />
       </taskdef>

       <!-- Compiles SBO interfaces-->
       <target name="compile-sbo-interfaces">
              <echo message="Compiling SBO interfaces ..." />
              <delete dir="${sbo.location}/build/interfaces" />
              <mkdir dir="${sbo.location}/build/interfaces" />
              <javac destdir="${sbo.location}/build/interfaces" excludes="com/example/sbo/impl/*.java" debug="true" debuglevel="${debuglevel}" source="${source}" target="${target}" encoding="8859_1">
                     <src path="${sbo.location}/src" />
                     <classpath refid="dfc.classpath" />
              </javac>
              <delete dir="${sbo.location}/dist/interfaces" />
              <mkdir dir="${sbo.location}/dist/interfaces" />
              <zip destfile="${sbo.location}/dist/interfaces/interfaces.jar" encoding="UTF8" duplicate="preserve">
                     <zipfileset dir="${sbo.location}/build/interfaces" includes="**/*.class" />
              </zip>

              <checkoutcheckin>
                     <docbaseobject jarfile="${sbo.location}/dist/interfaces/interfaces.jar " jarobject="SBO_example_interfaces" />
              </checkoutcheckin>

       </target>

Thank you for your attention, will see on next article ;) Feel free to comment.