Thursday, December 31, 2015

Two classes have the same XML type name?

When I'm generating the SEI stub object from a WSDL using following command:
   <plugin>
       <groupId>org.codehaus.mojo</groupId>
       <artifactId>jaxws-maven-plugin</artifactId>
       <executions>
         <execution>
           <goals>
             <goal>wsimport</goal>
           </goals>
             <configuration>
             <wsdlUrls>
               <wsdlUrl>http://localhost:8080/ws2?wsdl</wsdlUrl>
             </wsdlUrls>
           <keep>true</keep>
           <packageName>org.huahsin.jaxws.staff</packageName>
           <sourceDestDir>${basedir}/src</sourceDestDir>             
         </configuration>
         </execution>
       </executions>
   </plugin>
I'm not happy with the package name, so I decide to give a better name by changing the package name in a manual way. But when the client program trying to access the service:
 URL url = new URL("http://localhost:8080/ws2/SeniorManager?wsdl");
 QName qname = new QName("http://staff.huahsin.org/", "SeniorManagerService");
 SeniorManagerService service = new SeniorManagerService(url, qname);
 ISeniorManager manager = service.getSeniorManagerPort();
 System.out.println(manager.getID());
I hit this error:
Exception in thread "main" javax.xml.ws.WebServiceException: Unable to create JAXBContext
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:156)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.postProcess(AbstractSEIModelImpl.java:84)
 at com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:234)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.createSEIPortInfo(WSServiceDelegate.java:673)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.addSEI(WSServiceDelegate.java:661)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:330)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:313)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:295)
 at javax.xml.ws.Service.getPort(Service.java:119)
 at org.huahsin.jaxws.SeniorManagerService.getSeniorManagerPort(SeniorManagerService.java:72)
 at org.huahsin.Client.main(Client.java:23)
Caused by: java.security.PrivilegedActionException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://staff.huahsin.org/}getID". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetID
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetID(org.huahsin.jaxws.GetID)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetID
Two classes have the same XML type name "{http://staff.huahsin.org/}getIDResponse". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetIDResponse
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetIDResponse(org.huahsin.jaxws.GetIDResponse)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetIDResponse

 at java.security.AccessController.doPrivileged(Native Method)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:143)
 ... 10 more
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://staff.huahsin.org/}getID". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetID
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetID(org.huahsin.jaxws.GetID)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetID
Two classes have the same XML type name "{http://staff.huahsin.org/}getIDResponse". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetIDResponse
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetIDResponse(org.huahsin.jaxws.GetIDResponse)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetIDResponse

 at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:442)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:274)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:125)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1127)
 at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:173)
 at com.sun.xml.internal.bind.api.JAXBRIContext.newInstance(JAXBRIContext.java:95)
 at com.sun.xml.internal.ws.developer.JAXBContextFactory$1.createJAXBContext(JAXBContextFactory.java:98)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:151)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:143)
 ... 12 more
At first, this was really clueless to me. Spending day and night searching whatever clue appears on the stacktrace. And eventually I found nothing. Until in the late night only I found the out root cause. Never change the stub object's package name by hand, if the it does make some noise on you, delete the whole thing and regenerate again.

Like it or not, this is the way.

JAXWS and EJB can live together

If the SEI code were accessible from the client within the same package, do I still need the following code in order to access the service code?
   URL url = new URL("http://localhost:8080/ws1?wsdl");
   QName qname = new QName("http://webmethod.huahsin.org/", "HelloWorldImplService");
   HelloWorldImplService service = new HelloWorldImplService(url, qname);
   IHelloWorld manager = service.getHelloWorldImplPort();
   System.out.println(manager.sayHelloWorld());
Imaging I have the following SEI code and there are sit in the same application:
package org.huahsin.webmethod;
 
…
 
@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {
 
 @WebMethod
 String sayHelloWorld();
}
 
 
package org.huahsin.webmethod;
 
…
 
@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {
 
 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }
 
}
I just feel a bit weird in doing this since both client code and server code are live in the same application. I did a search on the forum and got to know that web service code can be accessed through EJB. Just "top up" the @Stateless and @Remote to the SEI and we are done.
@Remote
@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {
 
 @WebMethod
 String sayHelloWorld();
}
 
 
package org.huahsin.webmethod;
 
…

@Stateless
@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {
 
 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }
 
}
To access the web service code in EJB way, do the following (excuse myself, I'm doing it in JSF bean):
@ManagedBean
@RequestScoped
public class HelloWorldController {

 @EJB
 private IHelloWorld helloWorld;
 ...
 ...
Sound cool? The best part of this is no more generating stub code.

Saturday, December 26, 2015

Asynchronous web service is a real thing

It has been so long for my wish to come true. And finally, it is proven that asynchronous web service can be done. First, I make a regular SEI:
package org.huahsin.webmethod;

…

@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {

 @WebMethod
 String sayHelloWorld();
}


package org.huahsin.webmethod;

…

@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {

 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }

}
And then construct the following wsimport plugin in POM.xml to generate Java artifact. But this will only generate synchronous method.
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jaxws-maven-plugin</artifactId>
        <executions>
            <execution>
                <goals>
                    <goal>wsimport</goal>
                </goals>
                <configuration>
                    <wsdlUrls>
                        <wsdlUrl>http://localhost:8080/ws1?wsdl</wsdlUrl>
                    </wsdlUrls>
                    <bindingDirectory>${basedir}/resources/jaxws</bindingDirectory>
                    <keep>true</keep>
                    <packageName>org.huahsin.jaxws</packageName>
                    <sourceDestDir>${basedir}/src</sourceDestDir>             
                </configuration>
            </execution>
        </executions>
    </plugin>
To generate asynchronous method, I would require additional file to bind onto wsimport. It is just a regular XML file located at the path where <buildingDirectory> is pointing to, and the content is as shown in below:
<bindings
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="http://localhost:8080/ws1?wsdl"
    xmlns="http://java.sun.com/xml/ns/jaxws">

    <!-- applies to wsdl:definitions node, that would mean the entire wsdl -->
    <enableAsyncMapping>false</enableAsyncMapping>

    <!-- wsdl:portType operation customization -->
    <bindings node="wsdl:definitions/wsdl:portType [@name='IHelloWorld']/wsdl:operation[@name='sayHelloWorld']">
        <enableAsyncMapping>true</enableAsyncMapping>
    </bindings>
  
</bindings>
It's job scope is to locate the sayHelloWorld method using XPath and then convert this method to support asynchronous. While not affecting to the other's behaviour, I remain the rest of the methods as synchronous. Once everything is ready, I would first need a publisher to start the engine before I can do the conversion:
public class Publisher {
 public static void main(String args[]) {
  Endpoint.publish("http://localhost:8080/ws1", new HelloWorldImpl());
 }
}
Then fire the command mvn compile to generate Java artifact. This will have additional two methods generated for asynchronous (as shown in the code snippet below) compare to the default generation.
public interface IHelloWorld {
    public Response<SayHelloWorldResponse> sayHelloWorldAsync();

    public Future<?>sayHelloWorldAsync(
        @WebParam(name = "asyncHandler", targetNamespace = "")
        AsyncHandler<SayHelloWorldResponse> asyncHandler);

    ...
}
Now, to test my code is really works? I would have this simple program firing the asynchronous method:
...

import org.huahsin.jaxws.HelloWorldImplService;
import org.huahsin.jaxws.IHelloWorld;
import org.huahsin.jaxws.SayHelloWorldResponse;

...


public class Client {
 static private String msg = "";
 
 public static void main(String[] args) … {
  System.out.println("before: " + msg);
  e.sayHelloWorldMethod();
  Thread.sleep(1000);
  System.out.println("after: " + msg);
 }

 private void sayHelloWorldMethod() throws MalformedURLException, InterruptedException, ExecutionException {
  URL url = new URL("http://localhost:8080/ws1?wsdl");
  QName qname = new QName("http://webmethod.huahsin.org/", "HelloWorldImplService");
  HelloWorldImplService service = new HelloWorldImplService(url, qname);
  IHelloWorld hello = service.getHelloWorldImplPort();
  
  Response res = hello.sayHelloWorldAsync();
  SayHelloWorldResponse output = (SayHelloWorldResponse) res.get();
  output.getReturn();
  
  hello.sayHelloWorldAsync(new AsyncHandler() {

   @Override
   public void handleResponse(Response res) {
    try {
     setMessage(((SayHelloWorldResponse)res.get()).getReturn());
    }
    catch (InterruptedException | ExecutionException e) {
     e.printStackTrace();
    }
   }
   
  });
 }

 private void setMessage(String msg) {
   this.msg = msg;
 }

}

Thursday, December 24, 2015

HornetQ unable to validate the user

Oh shit!! Error again.
[WARNING] 
java.lang.reflect.InvocationTargetException
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:606)
 at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
 at java.lang.Thread.run(Thread.java:745)
Caused by: javax.jms.JMSSecurityException: HQ119031: Unable to validate user: null
 at org.hornetq.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:399)
 at org.hornetq.core.client.impl.ClientSessionFactoryImpl.createSessionInternal(ClientSessionFactoryImpl.java:880)
 at org.hornetq.core.client.impl.ClientSessionFactoryImpl.createSessionInternal(ClientSessionFactoryImpl.java:789)
 at org.hornetq.core.client.impl.ClientSessionFactoryImpl.createSession(ClientSessionFactoryImpl.java:324)
 at org.hornetq.jms.client.HornetQConnection.authorize(HornetQConnection.java:654)
 at org.hornetq.jms.client.HornetQConnectionFactory.createConnectionInternal(HornetQConnectionFactory.java:676)
 at org.hornetq.jms.client.HornetQConnectionFactory.createQueueConnection(HornetQConnectionFactory.java:119)
 at org.hornetq.jms.client.HornetQConnectionFactory.createQueueConnection(HornetQConnectionFactory.java:114)
 at org.huahsin.jms1.MetaData.main(MetaData.java:30)
 ... 6 more
Caused by: HornetQException[errorType=SECURITY_EXCEPTION message=HQ119031: Unable to validate user: null]
 ... 15 more
This time is HornetQ is unable to validate the user. I was running some test code on JMS which shows this:
 public static void main(String[] args) {
  Context context = null;
  QueueConnection qConn = null;
  final Properties env = new Properties();

  env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
  env.put(Context.PROVIDER_URL, System.getProperty(Context.PROVIDER_URL, "remote://localhost:4447"));
  env.put(Context.SECURITY_PRINCIPAL, System.getProperty("username", "quickstartUser"));
  env.put(Context.SECURITY_CREDENTIALS, System.getProperty("password", "quickstartPwd1!"));

  context = new InitialContext(env);
  String connStr = System.getProperty("connection.factory", "jms/RemoteConnectionFactory");
  QueueConnectionFactory factory = (QueueConnectionFactory) context.lookup(connStr);
  qConn = factory.createQueueConnection();

  ...
  ...
 }
Notice the createQueueConnection() taking empty arguments which cause this error. As of this writing, I'm using the following JMS maven configuration:
  <dependency>
    <groupId>javax.jms</groupId>
    <artifactId>jms</artifactId>
    <version>1.1</version>
   </dependency>
Actually, there is an overload method which taking additional two parameters that could pass the authentication. What frustrates me is that the intellisense only shows createQueueConnection(String arg0, String arg1). This shows the programmer is very a very irresponsible person. OK! Enough for that. By passing in the username and password, this would solve the problem.

Somehow there is a workaround for this, disable the HornetQ security in standalone-full.xml:
<hornetq-server>
    …
    <security-enabled>false</security-enabled>
</hornetq-server>
But I can't just so irresponsible to disable the security, right? I opt-out this workaround.

Better solution to exec:java in Maven

Hey! There is a simpler solution to execute a java program in Maven. Tracking back on my last development journey, there is a complicated way of doing this. Actually, I don't need any other except this:
<plugins>
      <plugin>
       <groupId>org.codehaus.mojo</groupId>
       <artifactId>exec-maven-plugin</artifactId>
       <version>1.4.0</version>
       <executions>
         <execution>
          <id>Meta</id>
          <goals>
            <goal>java</goal>
          </goals>
         </execution>
       </executions>
       <configuration>
         <mainClass>org.huahsin.jms1.QBorrower</mainClass>
       </configuration>
      </plugin>
      ...
      ...
</plugins>
And then just hit clean compile exec:java in Eclipse goal to execute the Java program.

Thursday, December 17, 2015

Wrong component? EJB can't used as web component?

Shit!! Something was wrong! When I deploy my web app into JBoss, it throws me this error:
(MSC service thread 1-2) MSC000001: Failed to start service jboss.deployment.unit."ejbWeb1.war".PARSE: org.jboss.msc.service.StartException in service jboss.deployment.unit."ejbWeb1.war".PARSE: JBAS018733: Failed to process phase PARSE of deployment "ejbWeb1.war"
 at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:127) [jboss-as-server-7.3.4.Final-redhat-1.jar:7.3.4.Final-redhat-1]
 at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.4.GA-redhat-1.jar:1.0.4.GA-redhat-1]
 at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.4.GA-redhat-1.jar:1.0.4.GA-redhat-1]
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_79]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_79]
 at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_79]
Caused by: java.lang.RuntimeException: JBAS018043: org.huahsin.ejb.Authentication has the wrong component type, it cannot be used as a web component
 at org.jboss.as.web.deployment.component.WebComponentProcessor.deploy(WebComponentProcessor.java:120)
 at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:120) [jboss-as-server-7.3.4.Final-redhat-1.jar:7.3.4.Final-redhat-1]
 ... 5 more
The clue is org.huahsin.ejb.Authentication can not be used as web component. Ok! Fine. What is the root cause of this? I'm gonna find out this...

I got an EJB code as stated below:
package org.huahsin;

@Remote
public interface AuthenticationRemote {
    public int status();
}

package org.huahsin;

@Stateless(name="authenticate")
@LocalBean
public class Authentication implements AuthenticationRemote {
    @Override
    public int status() {
        return 1234;
    }
}
This code was located in a standalone EJB project. And then I have another set of code which will accessing the EJB code:
package org.huahsin;

@WebServlet("/authentication")
public class Authentication extends HttpServlet {

 @EJB
 private AuthenticationRemote authenticationRemote;

 public Authentication() {
  super();
 }

 @Override
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
  int result = authenticationRemote.status();
  ...
  ...
 }
 
 @Override
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
  
 }
}
Yet, this is another web app project. So, to make these two projects work together, I did the following configuration on the web project:
  1. Reference the EJB project in Project References.
  2. Add EJB project in Web Deployment Assembly.
With the code flat on the plane, I think I have spotted the error. Notice that both web and EJB project having the same class name (Authentication) and package name (org.huahsin), this is where the error came from. Thus, rework on the code by placing org.huahsin.ejb for EJB project and org.huahsin.web for web project will solve this issue.

Tuesday, December 15, 2015

Filter file name with Boost regular expression

The story of the use case is like this; given a file name having the pattern, dummyx.txt, where x is a running number, how could I effectively filter out those doesn't match with this pattern? My initial answer would be this:
set<wstring> files = ... // assuming a list of file name are return and kept in the variable files

set<wstring>::iterator it;

for( it=list.begin(); it != list.end(); it++ ) {
    if ((*it).find(L"dummy.txt") != string::npos) {
        /***** proceed with the flow *****/
    }
}
I just feel that this piece is so rough. Instead of comparing the file name using wildcard search, I start to think of a more elegant way to get this done. So the first idea pops up in my mind is to use regular expression, here come to the second revision of the piece:
boost::regex expr("([\\:/\\\\\\w]+)?dummy(\\d{1,3})(\\.txt)$");
set<wstring>::iterator it;

for( it=list.begin(); it != list.end(); it++ ) {
    string s((*it).begin(), (*it).end());
    if (boost::regex_match(s, expr)) {
        /***** proceed with the flow *****/
    }
}
Much better? At least the code look much more elegant than the previous piece. Not only that it will filter out those doesn't match with the pattern, it will also filter out the name with only dummy in the file name.

Sunday, December 13, 2015

Install OpenGL libraries with NuGet Package Manager

Actually, there is a better way to install OpenGL libraries in visual Studio 2013 Express Edition. Now only I got to realize that there is a tool, a powerful tool to do this - NuGet Package Manager. But one requirement for this powerful feature to function is that the project must first create in order to proceed to the download. The reason being is the libraries will be installed under the particular project's path. It wasn't installed under the Program Files.

When I first initiate the Package Manager Console, I was greeted by a welcome message:
Each package is licensed to you by its owner. Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. Some packages may include dependencies which are governed by additional licenses. Follow the package source (feed) URL to determine any dependencies.

Package Manager Console Host Version 2.8.60610.756

Type 'get-help NuGet' to see all available NuGet commands.

PM>
And then type in Install-Package nupengl.core. Once done, this should be seen:
PM> Install-Package nupengl.core
Attempting to resolve dependency 'nupengl.core.redist (≥ 0.1.0.1)'.
Installing 'nupengl.core.redist 0.1.0.1'.
Successfully installed 'nupengl.core.redist 0.1.0.1'.
Installing 'nupengl.core 0.1.0.1'.
Successfully installed 'nupengl.core 0.1.0.1'.
Adding 'nupengl.core.redist 0.1.0.1' to OpenGl1.
Successfully added 'nupengl.core.redist 0.1.0.1' to OpenGl1.
Adding 'nupengl.core 0.1.0.1' to OpenGl1.
Successfully added 'nupengl.core 0.1.0.1' to OpenGl1.

PM>
When I first use this feature, I didn't know the project shouldn't close. End up I got this error:
PM> Install-Package nupengl.core
Install-Package : The current environment doesn't have a solution open.
At line:1 char:16
+ Install-Package <<<<  nupengl.core
    + CategoryInfo          : InvalidOperation: (:) [Install-Package], InvalidOperationException
    + FullyQualifiedErrorId : NuGetNoActiveSolution,NuGet.PowerShell.Commands.InstallPackageCommand
Ahhhh... so nice. This is far better than last time, everything was automated. Once I'm with done the installation, the first thing I do is to test the GL version installed in my machine:
int main(int argc, char** argv)
{
 ...

 glewInit();
 if (glewIsSupported("GL_VERSION_4_5"))
  std::cout << "GLEW version is 4.5" << std::endl;
 else
  std::cout << glGetString(GL_VERSION) << std::endl;

}
Unfortunately, I couldn't get my expected output. The output I got was 4.3.0 - Build 10.18.10.3995. Hmmm...

Clumsy mistake on Hibernate Filter

Before I met with Hibernate Filter, where clause would be my best friend doing the filtering in a query. Assuming I have a Use Case which will filter a date range from a resultset, this is what I usually did:
public void hibernateQuery() throws SQLException
{
 Configuration cfg = new Configuration();
 cfg.configure("hibernate.cfg.xml");
 SessionFactory fac = cfg.buildSessionFactory();
 Session s = fac.openSession();
 
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 Calendar cal = Calendar.getInstance();
 cal.set(2015, 0, 27);
 
 Query res = s.createQuery("from TheTable where to_char(parseDateTime(theDate, 'yyyy-mm-dd'), 'yyyy-mm-dd') = '" + 
               sdf.format(cal.getTime()) + 
               "'");
 List<thetablet> l = res.list();
 
 /***** process your data *****/

 s.close();
}
And this is the Hibernate construct of the table:
<hibernate-mapping>
    ...
    <class catalog="TEST" name="org.huahsin.model.TheTable" table="THE_TABLE">
        <property name="theDate" type="timestamp">
            <column length="23" name="THE_DATE" not-null="true">
        </column>
    </class>
</hibernate-mapping>
Notice the where clause is attached to the query and it is on object type. But with Hibernate Filter, the where clause will detach from the query and the filtering will be done in Hibernate construct. Just like this:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Filter filter = s.enableFilter("FilterByDate");

Calendar cal = Calendar.getInstance();
cal.set(2015, 0, 28);
filter.setParameter("beforeDate", sdf.format(cal.getTime()));

Calendar cal2 = Calendar.getInstance();
cal2.setTime(cal.getTime());
cal2.add(Calendar.DATE, 1);
filter.setParameter("afterDate", sdf.format(cal2.getTime()));

Query res = s.createQuery("from TheTable");
And the Hibernate construct would be like this:
<hibernate-mapping>
    ...
    <class name="org.huahsin.model.TheTable" table="THE_TABLE" catalog="TEST">
        ...
        <filter name="FilterByDate" condition="to_char(parseDateTime(THE_DATE, 'yyyy-mm-dd'), 'yyyy-mm-dd') between :beforeDate and :afterDate" />
    </class>
    <filter-def name="FilterByDate">
        <filter-param name="beforeDate" type="string"/>
        <filter-param name="afterDate" type="string"/>
    </filter-def>
</hibernate-mapping>
Notice the condition attribute (which is the same thing as where clause) was in pure SQL pattern. What a clumsy mistake I made was that I'm using Hibernate object in the condition attribute and causing the resultset return nothing. I'm just so clumsy!

Sunday, December 6, 2015

Hijacking the logger, so rude!

Last Friday could be my happiest day in 2015 because I've figured out how could I override log4j logger in unit test. Take the use case below as an example, I'll have the logger being declared as private static member:
import org.apache.log4j.Logger;

public class Helper {
   private static Logger jdbcLogger = Logger.getLogger("jdbcLogger");

   ...
   ...
}
This was a nightmare because JDBC logger is very high depends on the database's availability, especially when I've been told to freeze any update into the database. End up I create a local database just for this purpose, by doing so, I'm required to reconfigure the JDBC connection in my source code. This still isn't a clean solution as I don't want Jenkins to reconfigure the database configuration in the raw code. Then I start to think about the hijacking way, this is what I did to hijack the logger:
private void hijackJdbcLogger() {
   Logger l = Whitebox.getInternalState(Helper.class, "jdbcLogger");
   l.removeAllAppenders();
   l.addAppender(appender);

   Whitebox.setInternalState(Helper.class, "jdbcLogger", l);
}
But later I found out this solution has a flaw where jdbcLogger must first initialize by Helper class before I can change its value. At least I have something surprise me where I mock the whole logger:
@BeforeClass
public static void setUpBeforeClass() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
   Logger mockLogger = Logger.getLogger("unitTestLogger");
   mockLogger.setLevel(Level.DEBUG);
   mockLogger.setAdditivity(false);
   mockLogger.addAppender(EasyMock.createMock(ConsoleAppender.class));

   Field logger = ReportHelper.class.getDeclaredField("jdbcLogger");
   logger.setAccessible(true);
   logger.set(null, mockLogger);
}
Now I feel the perfection with this solution design. Again, in rule of design, hijacking is very rude, don't do this. When something has declared as private, meaning it is not suppose to be exposed to the outside world. Code review is indeed a higher priority in such case.

Tuesday, December 1, 2015

No last call on EasyMock

I have a static function which is as simple as following:
public class Utility {
   public static String funcA() {
      return "ABC";
   }
}
I was shock seeing the following error when I am unit testing the Utility class:
java.lang.IllegalStateException: no last call on a mock available
 at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:560)
 at org.easymock.EasyMock.expect(EasyMock.java:538)
 at org.huahsin.unittest.theprocess(SUT.java:72)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:606)
 at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
 at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88)
 at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
 at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
 at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
 at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
 at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
 at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
 at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
 at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
 at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192
The error message is quite confusing to me because this is to indicate that EasyMock was unable call the function as the function is being declared as static. Since EasyMock unable to handle static method, then PowerMock would be my best fit on this matter.

To allow EasyMock to see static method, I have to make an announcement to EasyMock that I'm sending in a class with static method and I'm going to unit test it now.
@RunWith(PowerMockRunner.class)
@PrepareForTest(Utility.class)
public class SUT {
   @BeforeClass
   public static void setUpBeforeClass() {
      PowerMock.mockStatic(Utility.class);
   }

   @Test
   public void theprocess() throws InvalidDataFileException {
      EasyMock.expect(Utility.funcA()).andReturn("genius");

      PowerMock.replayAll();

      /***** start test code when mock code are done *****/
   }
}
Then only EasyMock will know what to do. Do remember to call PowerMock.replayAll() to get the mock objects ready, otherwise EasyMock wouldn't recognize them.