IT Freelancer – Java, J2EE, IBM WebSphere Portal, Lotus Notes/Domino
RSS icon Home icon
  • Using EMF ECore model objects with Wicket components

    1 Star2 Stars3 Stars4 Stars5 Stars
    Loading ... Loading ...
    Posted on 8 September 2010 No comments

    Apache Wicket uses so called model objects to bind data objects to Wicket components. The framework provides a number of model implementations to access data objects and their properties in various ways. The PropertyModel implementation for example is used to access and set the value of a Java object using reflection.

    EPropertyModel

    If you are working with EMF (Eclipse Modeling Framework) generated model classes you can also use PropertyModels to bind structural features (properties in EMF terminology) of an EObject to a Wicket component. E.g. if your EObject has an attribute called “comment” you could instantiate a model like this

    IModel model = new PropertyModel(myEObject, "comment");
    

    This approach has several disadvantages. First, the name of the attribute is declared as a String and not as a compile-time reference to the actual attribute. This means the application could break during runtime if you have renamed the attribute at one point and forgot to also change the String value. Second, this property model uses runtime reflection which is a slow alternative to compile time based access.
    Java classes generated from EMF Models by default extend the EObject class which provides a compile-time reflection API. Using the generic eGet and eSet methods any public property of the EObject can be accessed. The EMF Generator also generates a Package class for each EMF package that holds a Literals interface listing all available attributes and references of all generated EClasses of the given package. If you lets say have an EClass “Ticket” with the attribute “comment” in the package “com.acme.service” you could utilize the compile time reflection API as follows:

    EAttribute commentAttribute = com.acme.service.ServicePackage.Literals.TICKET__COMMENT;
    Ticket newTicket = com.acme.service.ServiceFactory.eINSTANCE.create(Ticket.class);
    newTicket.eSet(commentAttribute, "my comment");
    

    Using the EMF compile-time reflection API I created a generic EMF ECore Feature Model implementation that leverages the compile-time references to structural features. Most of the code is actually related to working around the fact that EAttributes and EReferences are not serializable but which they should to be part safely referenced in a model that potentially is serialized by Wicket between requests.

    import org.apache.wicket.model.IDetachable;
    import org.apache.wicket.model.IObjectClassAwareModel;
    import org.eclipse.emf.ecore.EClass;
    import org.eclipse.emf.ecore.EClassifier;
    import org.eclipse.emf.ecore.EObject;
    import org.eclipse.emf.ecore.EPackage;
    import org.eclipse.emf.ecore.EStructuralFeature;
    
    /**
     * A property model to bind an attribute of an EMF ECore object
     *
     * @author Sebastian Thomschke
     */
    @SuppressWarnings("unchecked")
    public class EFeatureModel<T> implements IObjectClassAwareModel<T>
    {
    	private static final long serialVersionUID = 1L;
    
    	private transient EStructuralFeature feat;
    	private String featContainerClassName;
    	private String featName;
    	private String featPackageNsURI;
    
    	private EObject target;
    
    	public EFeatureModel(EObject target, EStructuralFeature efeature)
    	{
    		this.target = target;
    		this.feat = efeature;
    		this.featName = efeature.getName();
    		this.featContainerClassName = efeature.getContainerClass().getName();
    		this.featPackageNsURI = ((EPackage) efeature.eContainer().eContainer()).getNsURI();
    	}
    
    	public void detach()
    	{
    		if (target instanceof IDetachable) ((IDetachable) target).detach();
    	}
    
    	public EStructuralFeature getFeature()
    	{
    		if (feat == null)
    		{
    			EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(featPackageNsURI);
    			for (Object eClassifierItem : ePackage.getEClassifiers())
    			{
    				EClassifier eClassifier = (EClassifier) eClassifierItem;
    				if (eClassifier.getInstanceClass().getName().equals(featContainerClassName))
    					feat = ((EClass) eClassifier).getEStructuralFeature(featName);
    			}
    		}
    		return feat;
    	}
    
    	public T getObject()
    	{
    		return (T) target.eGet(getFeature());
    	}
    
    	public Class<T> getObjectClass()
    	{
    		return getFeature().getEType().getInstanceClass();
    	}
    
    	public void setObject(T object)
    	{
    		// do nothing if the object is the same instance that is returned by the getter
    		// this is esp. important for collection properties
    		if (target.eGet(getFeature()) == object) return;
    
    		target.eSet(getFeature(), object);
    	}
    
    	@Override
    	public String toString()
    	{
    		return new StringBuilder("Model:classname=[").append(getClass().getName()).append("]").append(":target=[")
    				.append(target).append("]").toString();
    	}
    }

    Using this new model implementation is as simple as using the PropertyModel provided by Wicket:

    IModel model = new EFeatureModel(myTicket, com.acme.service.ServicePackage.Literals.TICKET__COMMENT);
    

    You can now fully enjoy the compile-time safeness of your EMF model.

    Making EObjects serializable

    Wicket usually serializes components and their associated models between HTTP requests. If you are using the provided EPropertyModel your EObject classes must implement the Serializable interface. To achieve this, simply extend the EObject interface with the Serializables interface and set “Root Extends Interface” property in your genmodel configuration to this interface.

    /**
     * @author Sebastian Thomschke
     */
    public interface SerializableEObject extends EObject, Serializable {
    }
    

    When you now regenerate the model classes they will extend the SerializableEObject interface and Wicket will stop complaining about objects in the model being not serializable.

  • Installing Tomcat 6 on Debian Squeeze

    1 Star2 Stars3 Stars4 Stars5 Stars
    Loading ... Loading ...
    Posted on 13 March 2010 No comments

    This post describes how to setup Tomcat 6 on Debian Squeeze. The configured Tomcat serves requests on port 80 without the need of an additional web server. This is especially good for virtual servers (VPS) providing limit memory. It also has multiple virtual hosts configured, each with it’s own webapp with context root / and optional support for PHP via the Quercus PHP implementation.

    Installing Sun Java 6

    Ensure the non-free section is enabled for the APT repository configuration in /etc/apt/sources.list, e.g. “deb http://ftp.de.debian.org/debian testing main contrib non-free”

    apt-get update
    apt-get install sun-java6-jdk
    echo 'JAVA_HOME="/usr/lib/jvm/java-6-sun"' >> /etc/environment
    echo 'JRE_HOME="/usr/lib/jvm/java-6-sun/jre"' >> /etc/environment
    

    Installing Tomcat 6

    apt-get install tomcat6 tomcat6-admin
    /etc/init.d/tomcat6 stop
    

    Creating standard Tomcat directory layout

    mkdir /opt/tomcat
    cd /opt/tomcat
    ln -s /etc/tomcat6/ conf
    ln -s /usr/share/tomcat6/bin/ bin
    ln -s /usr/share/tomcat6/lib/ lib
    ln -s /var/lib/tomcat6/webapps webapps
    ln -s /var/log/tomcat6/ logs
    

    Creating a Tomcat admin user

    In /opt/tomcat/conf/tomcat-users.xml add an entry like:

    <user name="ADMIN_USERNAME" password="ADMIN_PASSWORD" roles="admin,manager" />
    

    Setting up virtual hosts

    For each virtual host execute the following command. Replace “mydomain.com” with the desired virtual host name, but omit the “www.” part.

    mkdir -p /opt/tomcat/webapps.mydomain.com/ROOT
    

    In the <Engine> tag of “/opt/tomcat/conf/server.xml” add one host entry for each virtual host.

    <Host name="mydomain.com" appBase="/opt/tomcat/webapps.mydomain.com">
        <Alias>www.mydomain.com>/Alias>
        <Valve className="org.apache.catalina.valves.AccessLogValve" prefix="mydomain_access_log." suffix=".txt" pattern="common"/>
    </Host>
    

    The <Alias> tag tells Tomcat to redirect from www.mydomain.com to mydomain.com.
    The <Valve> tag enables access logging in the standard logging format.

    Using xinetd to configure port 80 for Tomcat

    Binding a service on port 80 requires root permissions. Thus we use port forwarding to “bind” Tomcat to port 80. My VPS does not support the use of “iptables -j REDIRECT” therefore I am using xinetd as a web proxy.
    Ensure that no other service is listening on port 80/443:

    netstat -pan | grep ":80\|:443"
    

    Register the required xinetd services:

    echo echo "
    service www
    {
            socket_type     = stream
            protocol        = tcp
            user            = root
            wait            = no
            bind            = 88.80.198.181
            port            = 80
            redirect        = localhost 8080
            disable         = no
            flags           = REUSE
            log_type        = FILE /var/log/wwwaccess.log
            log_on_success  -= PID HOST DURATION EXIT
    
            per_source      = UNLIMITED
            instances       = UNLIMITED
    }
    
    service https
    {
            socket_type     = stream
            protocol        = tcp
            user            = root
            wait            = no
            bind            = 88.80.198.181
            port            = 443
            redirect        = localhost 8443
            disable         = no
            flags           = REUSE
            log_type        = FILE /var/log/httpsaccess.log
            log_on_success  -= PID HOST DURATION EXIT
    
            per_source      = UNLIMITED
            instances       = UNLIMITED
    }
    " > /etc/init.d/tomcat
    /etc/init.d/xinetd restart
    

    If you want to use a different service name, e.g. “tomcat” instead of “www” you must add this service to /var/services, e.g. “tomcat 80/tcp”
    In /opt/tomcat/conf/server.xml modify the <Connector> as follows:

    <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" proxyPort="80" address="127.0.0.1" />
    

    This binds Tomcat to localhost. It also tells Tomcat that port 80 is the proxy port which is necessary for correct URL generation.
    From now on the Tomcat admin applications are only accessible via localhost. You can use SSH port forwarding to still access the applications from your workstation’s web browser. E.g. if you are using PuTTY you can use this command line option “-L 8080:localhost:8080″ to forward the server’s local 8080 port to your workstation’s local 8080 port. On your workstation’s browser you then simply enter http://localhost:8080/manager/html and are connected to the server’s Tomcat admin application.

    Enabling PHP support (optional)

    Download Quercus.

    mkdir -p /opt/downloads
    wget -o /opt/downloads/quercus-4.0.3.war http://caucho.com/download/quercus-4.0.3.war
    

    Install Quercus as a shared library.

    unzip -j /opt/downloads/quercus-4.0.3.war \*.jar -d /opt/tomcat/lib
    

    Enable PHP support for the virtual hosts by installing the quercus web.xml. For each virtual host execute:

    unzip /opt/downloads/quercus-4.0.3.war *web.xml -d /opt/tomcat/webapps.mydomain.com/ROOT
    

    Starting Tomcat

    /etc/init.d/tomcat start
    

    References

  • getpass for Jython

    1 Star2 Stars3 Stars4 Stars5 Stars
    Loading ... Loading ...
    Posted on 21 November 2008 1 comment

    In my current project I am developing some Jython based command line tools and had the need for masking passwords entered in the command shell. Python provides the getpass module for this purpose. Unfortunately this module has not been made available for Jython.

    Here comes a module I wrote to provide this kind of functionality. It uses the mechanism described here http://java.sun.com/developer/technicalArticles/Security/pwordmask/ to mask characters entered at the command prompt. Additionally if Java 6 or higher is running Jython the module will instead use the new Console.readPassword() method. In case the module is running in an environment where the getpass module is available it will delegate to the corresponding methods of this module instead of using its own implementations.

    # ext_getpass.py
    # @author Sebastian Thomschke, http://sebthom.de/
    import thread, sys, time, os
    
    # exposed methods:
    __all__ = ["getpass","getuser"]
    
    def __doMasking(stream):
        __doMasking.stop = 0
        while not __doMasking.stop:
            stream.write("b*")
            stream.flush()
            time.sleep(0.01)
    
    def generic_getpass(prompt="Password: ", stream=None):
        if not stream:
            stream = sys.stderr
        prompt = str(prompt)
        if prompt:
            stream.write(prompt)
            stream.flush()
        thread.start_new_thread(__doMasking, (stream,))
        password = raw_input()
        __doMasking.stop = 1
        return password
    
    def generic_getuser():
        for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
            usr = os.environ.get(name)
            if usr: return usr
    
    def java6_getpass(prompt="Password: ", stream=None):
        if not stream:
            stream = sys.stderr
        prompt = str(prompt)
        if prompt:
            stream.write(prompt)
            stream.flush()
    
        from java.lang import System
        console = System.console()
        if console == None:
    	    return generic_getpass(prompt, stream)
        else:
            return "".join(console.readPassword())
    
    try:
        # trying to use Python's getpass implementation
        import getpass
        getpass = getpass.getpass
        getuser = getpass.getuser
    except ImportError, e:
        getuser = generic_getuser
    
        # trying to use Java 6's Console.readPassword() implementation
        try:
            from java.io import Console
            getpass = java6_getpass
        except ImportError, e:
            # use the generic getpass implementation
            getpass = generic_getpass
    

    Here is an usage example:

    import ext_getpass as getpass
    
    pw = getpass.getpass("Please enter your password:")
    print "The entered password was: " + pw
    
  • Sun JDK5/6 compilers broken when linking overloaded methods with variable arguments

    (4 votes) 1 Star2 Stars3 Stars4 Stars5 Stars
    Loading ... Loading ...
    Posted on 16 May 2008 1 comment

    We are currently switching the build system of OVal from custom Ant scripts to Maven 2. During that process we accidentally compiled the project using the Java compiler of the Sun JDK 5 instead of the AspectJ compiler. Surprisingly javac did not complain about the missing aspect class files. Instead it already aborted while compiling an ordinary Java class which only referenced other non-AspectJ related classes. This is the original error message:

    [INFO] [compiler:compile]
    [INFO] Compiling 180 source files to C:\projects\oval\src\trunk\target\classes
    [INFO] ------------------------------------------------------------------------
    [ERROR] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Compilation failure
    C:\projects\oval\src\trunk\src\main\java\net\sf\oval\Validator.java:[373,58]
    addMethodParameterChecks(java.lang.reflect.Method,int,java.lang.Object)
    has private access in net.sf.oval.internal.ClassChecks 

    There exist multiple methods named addMethodParameterChecks in the class ClassChecks with different signatures. The problem is that javac tries to link against the wrong method when compiling the class calling one of the methods.

    Read the rest of this entry »

  • Search

    Posted on 27 September 2007 No comments

    Google
    Web sebthom.de



  • OVal 1.0 released!

    1 Star2 Stars3 Stars4 Stars5 Stars
    Loading ... Loading ...
    Posted on 22 July 2007 No comments

    OVal is a pragmatic and extensible validation framework for any kind of Java objects (not only JavaBeans). Constraints can be configured with annotations, POJOs or XML. Custom constraints can be expressed in pure Java or by using scripting languages such as JavaScript, Groovy, BeanShell, OGNL or MVEL. Besides simple object validation OVal implements Programming by Contract features by utilizing AspectJ based aspects.

    Visit the project page at http://sourceforge.net/projects/oval/