Saturday, October 6, 2012

SIOCSIFFLAGS: Unknown error 132

If you encounter this error with hardware wlan switch not working in Suse (and possibly other distros as well). Do a simple thing before trying googled rfkills etc. Go to hardware/system settings and disable bluetooth there. Seems that problem with this Unknown error 132 has something to do with the fact that bluetooth/wlan are both switched on/off by the same button on most laptops. That is simple solution for non-working HW switch of wlan I used in OpenSuse 11.4.

Monday, July 4, 2011

Using Google Geocoding API for address validation


In e-commerce world it is very important to have valid and correct address base. Sending packages to an incorrect addresses causes
significant looses to eshops,when packages are not delivered and sent back to the eshop. In the kickz e-shop our customer had exactly those problems with many incomplete or incorrect returns due to bad addresses (especially from France). Thus we were thinking how to improve and force users to enter correct addresses. There are many commercial providers for addresses, however not all do have world address bases and as kickz is delivering to whole world it turned out that best value for money will be to use google geocoding web-service. Google has famous google maps application and as a side service they are providing either free or commercial web service for localisation of the position by GPS. So basically original idea of the service is to provide exact coordinates on the map for requested address. However as google response is not only the longitude/lattitude, this service might be used easily to refine addresses as well. That is exactly what we needed.
Basic geocoding api web service is free for 1000 requests per day and does not support https requests. As we did need https and more request per day, kickz has decided to go for paid service, which is unlimited and provides https URL with signed web-service requests.

Google web service is quite simple to use. All you need to do is send a simple http request to the specified address and you will recieve either xml or JSON response. Response might contain either one address or more addresses based on quality of input. It might as well be empty if google cannot locate your input address, but based on our experience it is rare case.Response in JSON is obvious choice for JavaScript (AJAX) based validation on client side, XML is more suitable for classic server side (request/response) validation. In kickz project we have chosen xml response option.In kickz shop we do validation through google WS everywhere, where user enters his address. This is either during customer registration or during checkout in shop. Request from browser is first sent to tomcat and on server side we do request to google WS signed with certificate and we process xml response returned and deserialise with JAXB to Java objects. After response is processed, user is shown options to refine his address entered in browser. Advantage of service is that all responses from google are localized. In the screenshots below you might see same validation once done in german shop and second time in international shop with different language parameters. Language parameter is set in the http request header with parameter "Accept-Language". To improve validation visually we do use also static google maps URL to show address graphically to the user.






Request

https://maps-api-ssl.google.com/maps/api/geocode/xml?address=Frankfurstein+ring+105a,M%C3%BCnchen,de,80000,&sensor=false&client=gme-kickzag&signature=RD8P7J07rJbfmClUeMEY4adIoTs=


Response

<GeocodeResponse> 
    <status>OK</status> 
    <result>  
        <type>street_address</type>  
        <formatted_address>Frankfurter Ring 105, 80807 Munich, Germany</formatted_address>  
        <address_component>   
            <long_name>105</long_name>   
            <short_name>105</short_name>   
            <type>street_number</type>  
        </address_component>  
        <address_component>   
            <long_name>Frankfurter Ring</long_name>   
            <short_name>Frankfurter Ring</short_name>   
            <type>route</type>  
        </address_component>  
        <address_component>   
            <long_name>München</long_name>   
            <short_name>München</short_name>   
            <type>sublocality</type>   
            <type>political</type>  
        </address_component>  
        <address_component>   
            <long_name>Munich</long_name>   
            <short_name>Munich</short_name>   
            <type>locality</type>   
            <type>political</type>  
        </address_component>  
        <address_component>   
            <long_name>Munich</long_name>   
            <short_name>M</short_name>   
            <type>administrative_area_level_2</type>   
            <type>political</type>  
        </address_component>  
        <address_component>   
            <long_name>Bayern</long_name>   
            <short_name>BY</short_name>   
            <type>administrative_area_level_1</type>   
            <type>political</type>  
        </address_component>  
        <address_component>   
            <long_name>Germany</long_name>   
            <short_name>DE</short_name>   
            <type>country</type>   
            <type>political</type>  
        </address_component>  
        <address_component>   
            <long_name>80807</long_name>   
            <short_name>80807</short_name>   
            <type>postal_code</type>  
        </address_component>  
        <geometry>   
            <location>    
                <lat>48.1883675</lat>    
                <lng>11.5857053</lng>   
            </location>   
            <location_type>ROOFTOP</location_type>   
            <viewport>    
                <southwest>     
                    <lat>48.1852199</lat>     
                    <lng>11.5825577</lng>    
                </southwest>    
                <northeast>     
                    <lat>48.1915151</lat>     
                    <lng>11.5888529</lng>    
                </northeast>   
            </viewport>  
        </geometry>  
        <partial_match>true</partial_match> 
    </result>
</GeocodeResponse>



Conclusion

Google geocoding web service turned out to be effective tool for validation of the user addresses in kickz eshop. Furthermore this service might be used free of charge for small projects or pages with lower traffic. In kickz though we are using paid version of web service as traffic is higher and we do need https service URL. You can find more information about the web service URLs etc. on Geocoding API webpage.

Friday, April 8, 2011

Lucene as No-SQL database

Lucene is an excellent library for performing full text searching. It is very powerful with quite easy and understandable API.
Mostly it is used as an engine for full text search. In the recent project have decided to use Lucene bit non-standard way as no-sql store.


In relational database you might have quite complex relations between tables and corresponding Java entities (using Hibernate in this case).
However for some use cases what you really need is simple representation of the object you present to the user with all the data present on that object.
In this case it was used for e-shop catalog. So first of all you have DB model and you transform it to the Lucene Document including all the necessary information you need.


Mapping entity relations to the flat Lucene document.


So you simplify the relational model in DB to the flat structure of the documents with required parameters. In this case what you need in document is what you want to show to the user and eventually what user might limit/change/adjust to refine his search criteria (like size, color, brand, category etc.). So practically we do create index of Document's , which does hold all necessary informations to build a search criteria and limit the result returned by Lucene. Furthermore there is an option in Lucene to store/not-store data in index and to index analyzed data (for fulltext queries) or to store just unanalyzed data (for parameter search - like size, category, brand).


Once you have lucene index built you are getting very effective data structure, which does not contain complicated relational data and is also much smaller then all data in the database.Motivation of this approach was to speed up searching based on multiple criterias, which are changing dynamically and quickly (each user might combine very different criterias to refine his search). Lucene turned out as very good performing for this purpose and you are not limited by complicated SQL queries to much bigger DB tables. You are getting powerful non-sql structure, which might be queried kind of SQL-way in combination with full text searching.


Limitation and problem of using Lucene as storage is if you need to change your relational mappings or data very frequently - then you would need to frequently rebuild lucene index and it might be a bottleneck in some cases.

Thursday, March 10, 2011

Spring managed service classes post-initialization using transaction template

In my recent work , where we do use Hibernate and Spring for services I encountered a common problem with initialization of the services, which do need to have already transaction management initialized before they are executed. If you got a managed Spring beans and you would like to do some post processing of the managed bean you might use standard @PostConstruct annotation, which is processed after the BeanFactory creates the bean. Unfortunately there is no guarantee that in the time of calling @PostConstruct all other managed beans are properly initialized yet and transaction management is not initialized as well. So problem is if  you need to initialize some services at startup, which do need access to the hibernate session and spring transaction management. You could use @PostInitialize annotation. Unfortunately even though this is a good approach I have encountered a problems even with this post processor in combination with annotation @Transactional. Simply if you have called a method annotated with both of the annotations then in some cases it still was giving well-known error

"Caused by: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here"

Consider code snippet below.

Example 1:

This is example service class:

@Service
public class Service{

    @Transactional
    @PostInitialize
    public void initMethod(){
      
         daoService.doSomeWork();
    }
}


Here is DAO class:

@Repository
public class DaoService{

    public void doSomeWork(){
    }
}

I have realized that in some cases @PostInitialize has been working, but I needed to put @Transactional annotation into the DaoService as well. Thus after some time playing around with this custom annotation  I realized this is not a good approach. So finally I have used simple, but reliable approach for initialization of the spring managed services, which do need to get hibernate session.

I have defined a transaction template in spring context.xml (you might specify paremeters of the transaction):

<bean id="sharedTransactionTemplate"

      class="org.springframework.transaction.support.TransactionTemplate">

     <property name="transactionManager" ref="transactionManager"/  >

</bean>

Then I have defined kind of base class for all service which do need to be initialized within transaction:
@Service
public class SpringInitializedService implements ApplicationListener<SpringContextInitialized> {

 
    @Inject
    private TransactionTemplate tt;
    private static final Log log = LogFactory.getLog(SpringInitializedService.class);

    public SpringInitializedService() {
    }
  
    public SpringInitializedService(PlatformTransactionManager tm){
        tt.setTransactionManager(tm);
    }

    @Override
    public void onApplicationEvent(SpringContextInitialized event) {
        tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try{
                initialize();
                }
                catch (Exception ex){
                    log.error("Error during initialization",ex);
                    status.setRollbackOnly();
                }
            }
        });

    }
    public void initialize(){
    }

Now managed service classes, which do need transaction (and hibernate session) during initialization  just need to extend this class and override initialize() method with its own code. Last step is to fire SpringContextInitialized event , when spring context is initialized and you are done. Some adjustments of this approach would be needed if you need to affect the order of the initialized services, but this was not my case so I did not care about that.