вторник, 16 ноября 2010 г.

Share smartgwt js over several gwt modules

When you create smartgwt module you have the following lines in your *.gwt.xml file:

...
<inherits name="com.smartgwt.SmartGwt"/>
...

Everything works fine. When you load your module at the first time, the browser gets all smartgwt js libs(ISC_*.js) and caches it. In our application we have got five gwt modules and all of them are using smartgwt. And when we load each module for the first time, it is getting 2 MB of js files. For our five modules browser downloads over 10 MB of smartclient libs. That's too much! To solve this problem I discover SmartGwt.gwt.xml. It inherits from module that called SmartClientDefault:


<module>
<script src="sc/modules/ISC_Core.js"/>
<script src="sc/modules/ISC_Foundation.js"/>
<script src="sc/modules/ISC_Containers.js"/>
<script src="sc/modules/ISC_Grids.js"/>
<script src="sc/modules/ISC_Forms.js"/>
<script src="sc/modules/ISC_RichTextEditor.js"/>
<script src="sc/modules/ISC_Calendar.js"/>
<script src="sc/modules/ISC_DataBinding.js"/>
</module>

And that's our problem. All js have relative paths. But Smartgwt has wonderful module that called SmartGwtNoScript that does not have a dependence on SmartClientDefault and we can include all scripts using absolute paths!
The solution is to replace inherits from com.smartgwt.SmartGwt by the following code in all modules that need smartgwt(or create one root module):


<inherits name="com.smartgwt.SmartGwtNoScript"/>
<script src="/mod/sc/modules/ISC_Core.js"/>
<script src="/mod/sc/modules/ISC_Foundation.js"/>
<script src="/mod/sc/modules/ISC_Containers.js"/>
<script src="/mod/sc/modules/ISC_Grids.js"/>
<script src="/mod/sc/modules/ISC_Forms.js"/>
<script src="/mod/sc/modules/ISC_RichTextEditor.js"/>
<script src="/mod/sc/modules/ISC_Calendar.js"/>
<script src="/mod/sc/modules/ISC_DataBinding.js"/>

вторник, 9 ноября 2010 г.

Simplify if

From time to time we write unoptimized code. For program to be cute it is fun to be optimized.
For example this is a possible way to write if sequence:

if (p.equals("Completed")){
return true;
} else {
return false;
}

But to be optimized the method body should look like this:

return "Completed".equals(p);


What's really interesting is that it's not only looking good. Indeed it helps you to evade null pointer exception in case when p equals null. We are not able to call method from null - it'll throw exception, but when using equals() method this would be processed correctly.

To study this in depth we can explore StringUtils.java (the one that is in org.apache.commons.lang package).


public static boolean equals(String str1, String str2) {
return str1 == null ? str2 == null : str1.equals(str2);
}


Lets look at the method in JAVA source code and the values it may return:

StringUtils.equals(null, null) = true
StringUtils.equals(null, "abc") = false
StringUtils.equals("abc", null) = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false


It returns true in case of equality. So, we can use this or the same logic to write our optimized pieces of code.

Have fun, optimize :)

четверг, 4 ноября 2010 г.

Height for DateChooser (Smart GWT)

In our project we are using Smart GWT component (DateChooser) which allows user to select dates ranges. It looks like this:
date chooser height bug.

Smart GWT has a bunch of useful things (datasources, for example). But when I need some UI customization, sometimes I am having troubles :) And now I've got problems with height of the DateChooser component.

Both date choosers have height 200 px, but the right one is smaller then the left because it has only five week rows. Our tester is very carping guy :) though he had posted a bug in the bug tracker. I had spent some time and found a solution. All that I needed was to wrap DateChooser in a layout. I wrote simple helper method for doing this:

    public static Canvas wrapDateChooser(DateChooser dateChooser, String width, String height) {
        VLayout layout = new VLayout();
        layout.addMember(dateChooser);
        layout.setWidth(width);
        layout.setHeight(height);
        dateChooser.setHeight(height);
        return layout;
    }

Result:
fixed date chooser bug

Go and close bug in JIRA, YEAH!

пятница, 24 сентября 2010 г.

Wrote test, use mockito...drink mockito!

Hi all!

In our project we have parts that are written by our outsource partners. We are using their services in our code. Services injected from spring to our beans.

Yesterday, they made a weekly commit, and I've found out that my tests were broken :( One of their developer had commented my stub that implemented their interface. They said that he didn't want to change any code although I needed my stub to collect and analyze input in it.

I started solving this problem learning about mock objects. On my previous work, one of my coworkers used mockito and he liked it a lot :) I've found the information about it here: site. I suppose it's good that the last version was released in may. Also, I like projects that have good documentation and have *-all.jar. Mockito has all of that!

I needed only one method from two interfaces. And I've written simple mock objects and inject this mocks in spring.


SomeService mockService = Mockito.mock(SomeService.class);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
String[] users = (String[])invocation.getArguments()[0];
String title = (String)invocation.getArguments()[1];
//Collect information here.
return null;
}
}).when(mockService).
someMethod(Mockito.<string[]>any(), Mockito.anyString());

Also, I have got some troubles when injecting this service in spring: I could not do something like this:
myService.setSomeService(mockService);

because I am using @Transactional and having Proxy object. After some google searches I've found solution for this(I think, that it's not ideal, because I found some info about @Configurable beans and wrote TODO ;))

((MyServiceImpl)( ((Advised)myService).getTargetSource().getTarget())).setSomeService(mockService);


I commited this and...drink mockito :)!

среда, 1 сентября 2010 г.

Authentication problems in multithreading

In my application, I have a tree widget that using ajax for loading nodes. Tomcat create some threads to service requests. Each requests validate security ticket that stores in http session:

authenticationService.validate(ticket, null);

And some threads can not validate this ticket and service throws AuthenticationException. If you have particular problem, then you should look at alfresco's jira: ALF-3789. This bug was fixed in revision 21065 at trunk. To fix it in my code, I simple override bean:

<!--Override alfresco-->
    <bean name="ticketsCache" class="org.alfresco.repo.cache.EhCacheAdapter">
       <property name="cache">
          <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean" >
             <property name="cacheManager">
                <ref bean="internalEHCacheManager" />
             </property>
             <property name="cacheName">
                <value>org.alfresco.cache.ticketsCache</value>
             </property>
          </bean>
       </property>
    </bean>

After this all works fine :)

пятница, 20 августа 2010 г.

Fun with alfresco types.

Good day!

Yesterday, I had some fun with alfresco types and permissions. I've created simple type in my model that looks like this:
<type name="my:simpleType">
  <title>Simple type</title>
  <properties>
    <property name="my:prop">
       <type>d:int</type>
    </property>
  </properties>
</type>

I've included it as child-association to the other type and tried to create it:
Node simpleProp = parentNode.addProperty("my:parentProp", "my:simpleType");
  simpleProp.setProperty("my:prop", 1);//AccessDeniedException here!

But, when I ran JUnit test, it threw AccessDeniedException on setProperty for that node. I started debugging alfresco sources, but still I couldn't understand what is going on. Why can I create parent node, add node to association, but can not set property for this node???!!! I tried to use NodeService without JCR API, but I've got the same trouble. Then, I discovered all sources of alfresco's permission subsystem(PermissionServiceImpl, SecurityProvider, etc) with acegi, but still in vain :(

By the end of the day, I have got two cigarettes and zero ideas. After first cigarette, I was looking at my model trying to find problem and finally I've got it! My new type had no parent type! When I added
<parent>cm:content</parent>

everything worked fine! That was hard day: one day - one string...fast work :)

среда, 4 августа 2010 г.

Search content by dates in alfresco using CMIS API

Hi all!

I have a new project that use Alfresco as a backend to store content. I need select content by date. User specifies dates and the service should find and display it. I've chosen CMIS API. It supports query language like SQL to get content. But I've got a problem. I need to specify the date in my query, that looks like this:
SELECT * FROM my:content WHERE my:modifyDate < 01.01.2010
My problem is a date format. In alfresco wiki, I found this description:
datetime literals Based on SQL-92 with 'T' replacing in ,
But it doesn't work. Why???!!! Because I had simply copy-pasted the format for SimpleDateFormat: yyyy-MM-dd'T'HH.mm.ss.SSS. Next hour I could not get why it doesn't work. That format is wrong and must be: yyyy-MM-dd'T'HH:mm:ss.SSS'Z' Also, in alfresco SVN and I've found a good helper class for this: org.alfresco.util.CachingDateFormat. But I didn't hav it in my build of alfresco(I use community build version 3.3, but it was build early). When I upgrade, I will use this class, but for now I wrote simple type helper that looks like this:
package com.blogspot.jajatips.alfresco.util;

import org.apache.commons.lang.time.FastDateFormat;
import java.util.Date;

/**
 * Date: 03.08.2010
 * @author Dmitry N. Pokidov
 */
public class TypeHelper {
    public static String formatDate(Date date) {
        //TODO: CachingDateFormat.getCmisSqlDatetimeFormat()
        FastDateFormat cmisDateFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ");
        return new StringBuilder("TIMESTAMP '").append(cmisDateFormat.format(date)).append("'").toString();
    }
}
As you can see, I use FastDateFormat from common-lang, that cache date formats. Also, their formats are thread safe, which is very important if you have some static queries.

Well, I'm going to request to make changes in SimpleDateFormat in alfresco wiki, so no one would have this trouble :)

UPD: Good news, I have fixed alfresco wiki page :)

понедельник, 18 января 2010 г.

Getting changes from collection

Good morning :)

Usually to update some entities in database I use service that must be calculate changes from new and old object and update changes in database(using DAO, for example). And the common task is update collections. I wrote simple class that calculate changes from old and new collections and create three collections: to delete, to update and to create. You can see class below and some description for it

package com.blogspot.jajatips.utils;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;

public class ChangesCollections<T> {
 private static class CollectionFactory<T> {
  private static final Log log = LogFactory.getLog(CollectionFactory.class);
  private Class<? extends Collection> classCollection = ArrayList.class;

  private CollectionFactory(Class<? extends Collection> classCollection) {
   this.classCollection = classCollection;
  }

  @SuppressWarnings("unchecked")
  public Collection<T> getNewCollection() {
   try {
    return classCollection.newInstance();
   } catch (Exception e) {
    log.warn("Can not create collection for class [" + classCollection.getName() + "], create java.util.ArrayList");
    return new ArrayList<T>();
   }
  }
 }

 private Collection<T> deleteCollection;
 private Collection<T> addCollection;
 private Collection<T> updateCollection;

 public ChangesCollections(Collection<T> oldCollection, Collection<T> newCollection) {
  CollectionFactory<T> factory = new CollectionFactory<T>(oldCollection.getClass());

  this.deleteCollection = factory.getNewCollection();
  this.addCollection = factory.getNewCollection();
  this.updateCollection = factory.getNewCollection();

  addCollection.addAll(newCollection);
  deleteCollection.addAll(oldCollection);
  Iterator<T> addIt = addCollection.iterator();
  while (addIt.hasNext()) {
   T addObject = addIt.next();
   if (contains(oldCollection, addObject)) {
    updateCollection.add(addObject);
    deleteCollection.remove(addObject);
    addIt.remove();
   }
  }
 }

 public Collection<T> getDeleteCollection() {
  return deleteCollection;
 }

 public Collection<T> getAddCollection() {
  return addCollection;
 }

 public Collection<T> getUpdateCollection() {
  return updateCollection;
 }

 private boolean contains(Collection<T> collection, T object) {
  if (object.getClass().isAssignableFrom(Predicate.class)) {
   return CollectionUtils.exists(collection, (Predicate) object);
  }

  return collection.contains(object);
 }
}

First of all, to build this code you need next libraries: commons-collections and commons-logging. Also, I like generics and use it in all my code, because I like compile errors more than runtime errors :).
Now, about the code. To create collections, I use inner class CollectionFactory, that try to create class of collection same as original collection, if it can not do this, it create standard java.util.List. As you can see, code is simple. All that it done is iterate over collections and put elements in other three collections.

I hope that this class helps you in your projects :)

Most popular

Authors