Translate

Mostrando entradas con la etiqueta Spring. Mostrar todas las entradas
Mostrando entradas con la etiqueta Spring. Mostrar todas las entradas

domingo, 23 de marzo de 2014

MongoDB Spring Security Code Example

Titulo: Ejemplo práctico de Spring Security con MongoDB con código fuente.

I have decided to change the main language of my blog in order to reach and share everything with more people.

In this post you can see the next topics

- SpringData With MongoDb Integration
- Spring MVC to manage navigation
- Spring Security with Custom user detais service to assign roles and web application authentication.




Everything is easy and separated in different files to be more understandable and you have all the code in github.

This example is based on the book Spring Security 3.x Cookbook  that cover a lot of spring security integrations with different technologies:
  1. ORM (Hibernate) and NoSQL Databases (MongoDB) 
  2. JSF
  3. JSP
  4. Struts 2
  5. GWT
  6. Grails
  7. Vaadin
  8. Wicked
  9. Facebook, Twitter
  10. WebServices: RESTFull, SOAP
  11. Captcha Integration
  12. and more all with code samples
After this recommendation, lets go to show the example, all the code you can find it in my GitHub repository.

Please download the code as ZIP or fork the repository to follow the example.

To run the example you have the following requirements:
1- Eclipse Kepler to import the project from github or zip file.
2 - Document data base MongoDB installed in the same machine as your application server.
3 - Application Server Apache Tomcat 7
4 - Configure your application path context to "/" in ordet to Spring Security secure your URL.



Import the project into eclipse like a Maven project and deploy it in a Tomcat server sever with the above path configuration.

Populate you MongoDB database with users data, you can do it easily executing this test file in the application.UserPopulateCollection.java

Remember to uncomment the //@Test line.



or insert in the Mongo Database the next data into User Collection




The application  is a 4 screens application, we have a Login page where you can login like:

1 - Admin User (Role 1 - ROLE_ADMIN): You can access to User and Campaign pages but not create new campaigns.
2 - Campaign User (Role 2 - ROLE_CAMPAIGN): You only can access to Campaign page and create new one, but you can not access to users pages.


You can access the application from the following url using any of these users

http://localhost:8080/login

User Admin
user: user1@antuansoft.es
pwd: 123

User Campaign
user: user2@antuansoft.es
pwd 123


Menu page with the different application´s options Users and Campaings.



Users page where you have all the info about your application users.




Campaing page where you can access to all information of your campaings and can add and delete it



I think it's time we have a look at the project configuration files,

A - pom.xml

In this file you can see al the dependencies that we need, all of this related with Spring and MongoDB.

B - web.xml

Here we have the main project configuration, where the application server starts reading de config files.

Open the file in github or in your eclipse project and you can see:
1- The Spring Security filter configuration to secure all the URLs
2 - Spring MVC servlet dispatcher to manager all the URL requests.
3 - Log4J configuration
4 - Spring modules (Spring Data, Spring Security, Spring MVC) configuration files

 <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>
      /WEB-INF/mvc-config.xml
      /WEB-INF/security-config.xml       
      /WEB-INF/mongo-config.xml
     </param-value>
 </context-param>
        

C - mvc-config.xml

In this file there are the basic MVC configuration and packages to scan.

1 - Set the Spring context to  manage requests with the Spring MVC Controllers with the tag        <mvc:annotation-driven />
2 - Set the packages to scan Spring beans annotated with @RequestMapping @Component, etc...

  <context:component-scan base-package="com.antuansoft.spring.mvc">  
  <context:component-scan base-package="com.antuansoft.spring.security">  

3 - Define the views configuration location ant type, in this case with jsp, using JSTL.

D - mongo-config.xml

Here we have the MongDB configuration

1 - We define the database parameters, host and port and the database name in the mongoDbFactory. This is the main configuration to connect with database.

2- Define the MongoRepositories, this is where Spring Data is going to scan to look for Mongo DAOS (Mongo Data Acces Objects). In this DAOS is where all the database operations (save, delete, etc.) and the domain objects (User, and Campaign) are defined.

<mongo:repositories base-package="com.antuansoft.mongodb.repositories" />

E - security-config.xml

The security configuration of the application is defined here.

1 - Enable the @PreAuthorize annotation that will be user in MainController class

2 - Secure the application´s  urls. Due to this config is important to change the application path context to "/" like we said above.
   - /login, /logout and /accessdenied urls are permited to authenticated and not  authenticated users.
   - to access to /menu you have to be authenticated with ROLE_ADMIN or ROLE_CAMPAIGN
   - to access to /listUsers you have to be authenticated with ROLE_ADMIN
   - to access to /listCampaigns you have to be authenticated with ROLE_ADMIN or ROLE_CAMPAIGN
   - Finally the spring security login form is too easy to understand.


3 - The most important part is the definition of a custom class (mongoUserDetailsService) to authenticate users application access. An the password encoding, here we use plain text but  i recommend  to use MD5.

<authentication-manager alias="authenticationManager">
 <authentication-provider user-service-ref="mongoUserDetailsService">
   <password-encoder hash="plaintext" />
  </authentication-provider>
 </authentication-manager>

After configuration files we are going to review the specific Java files to understand the Spring Data, Spring Mvc and Spring Security features.

Spring Security:

Open the file MongoUserDetailsService.java

This is the file we have defined in security-config.xml as the authentication provider, this class have to implement the SpringFramework interface UserDetailsService and create the method UserDetailsService.

This method is used to check if the user data send in login form is valid against your database info, this method have to return a org.springframework.security.core.userdetails.User class with the data of the user found in your database.

You have to query your user collection and get the user info, we use the method getUserDetail that call to userRepositoryDao.findByUsername(username);

After getting  user info and based on this, the user role is defined in getAuthorities method.and pass it to UserDetails object.

getUserDetail  and getAuthorities are two methods that you can customize to set the authentication and the user Rols according yo your requirements.

 private org.springframework.security.core.userdetails.User userdetails;
 public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        boolean enabled = true;
        boolean accountNonExpired = true;
        boolean credentialsNonExpired = true;
        boolean accountNonLocked = true;
        com.antuansoft.mongodb.domain.User user = getUserDetail(username);
        
        userdetails = new User(user.getUsername(), 
                    user.getPassword(),
                    enabled,
                    accountNonExpired,
                    credentialsNonExpired,
                    accountNonLocked,
                    getAuthorities(user.getRole()));
            return userdetails;
    }

    public List getAuthorities(Integer role) {
        List authList = new ArrayList();
        if (role.intValue() == 1) {
            authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

        } else if (role.intValue() == 2) {
            authList.add(new SimpleGrantedAuthority("ROLE_CAMPAIGN"));
        }
        System.out.println(authList);
        return authList;
    }

    public com.antuansoft.mongodb.domain.User getUserDetail(String username) {
     com.antuansoft.mongodb.domain.User user = userRepositoryDao.findByUsername(username);
        //System.out.println(user.toString());
        return user;
    }


MongoDB:

Here we have two things to consider, Domain classes and Dao interfaces.

1 - Domain classes

This classes are plain old java objects (pojos) to define the data of your database collections, in other words the objects that your are going to persists in your database.

Look at the com.antuansoft.mongodb.domain packge and you will find the two documents that we are going to use in this application. User and Campaign.

The only thing that is special in the classes is that they are annotated with @Document and specify a collection where this pojo will be stored.

@Document(collection = "campaign" )
public class Campaign {


You can open this file to see that.

Campaign.java
User.java

2 - DAO interfaces:

Dao interfacesare in com.antuansoft.mongodb.repositories package and here is where all the database operations (save, delete, etc.) and the domain objects (User, and Campaign) are defined.

In mongo-config.xml file we have defined this package to be scanned to look for mongo repositories, its means that Spring Context transform this interfaces in a DAO object with all the basic operations like create, read, update,delete where we can use in the application.

This classes only have to extend from org.springframework.data.repository.CrudRepository to work.

--
public interface UserRepositoryDao extends CrudRepository<User, String> {
 
 
 public User findByUsername(String username);

}

--

This Crud repository has two params <User, String>, here is  where bind the User domain pojo to this Repository Dao. Here we indicate that this Dao process User Object and the ID´s type is String.

In UserRepositoyDao there is something special, it is a special method user for authentication findByUsername. Another feature of SpringData is that you can define query methods without write any line of code.

Here we have defined a query to find a user by a username, only with key words. find+By+field to query in user pojo object (findByUsername). And it´s work!!!! is magic!!

Spring MVC:

Finally the only thing that we have to review is the controller that allows us to navigate through the application.

The MainController class is a basic class that use the SpringMVC annotations, @RequestMapping,  to navigate:

@RequestMapping(value = "/listCampaigns", method = RequestMethod.GET)
 public String listCampaigns(ModelMap map) {
  
  map.addAttribute("new_campaign", new Campaign());
  Iterable campaings= campaignRepositoryDao.findAll();
  map.addAttribute("campaigns",campaings);
  
  return "listCampaigns";
 }


and basically it means that when SpringMVC detects this urls the method will be executed, in this case the method pass to listCampaigns.jsp all the campaings and new campaing object.

In this class we have a little special thing that add a spring security functionality, it´s the @PreAuthorize annotation that only allow to ROLE_CAMPAIGN users to add a new Campaign.


@PreAuthorize("hasRole('ROLE_CAMPAIGN')")
 @RequestMapping(value = "/addCampaing", method = RequestMethod.POST)
 public String addCampaign(@ModelAttribute(value = "new_campaign") 
                                  Campaign new_campaign,
             BindingResult result){
  
  new_campaign.setId(UUID.randomUUID().toString());
  campaignRepositoryDao.save(new_campaign);
  
  return "redirect:/listCampaigns";
 }

And this its all, i thinks that it is a complete example a not too difficult to understand.

Remember that you have all the code in my GitHub repository.


References:

Mainly Spring Security 3.x Cookbook

Spring Data MongoDB
Spring Security
Spring MVC


domingo, 9 de febrero de 2014

Ejemplo fácil de Spring REST con código fuente

Este es una ejemplo que me ha parecido muy útil y sencillo realizado por,  , un miembro la comunidad Spring en Linkedin.



Lo tiene muy bien explicado en un vídeo que os pongo a continuación y el código en github, que también os pongo. Además su inglés se entiende muy fácilmente.




Código fuente en github


miércoles, 11 de septiembre de 2013

Error usando Junit combinado con AspectJ: AspectJAdviceParameterNameDiscoverer$AmbiguousBindingException

En nuestro proyecto J2EE hemos utilizado AspectJ para capturas las excepciones que se producen en la parte servidora en JAVA.

Es muy cómodo porque no tienes que poner bloques try....catch en todos los servicios de la aplicación para aplicar la gestión que quieras a las excepciones, de este modo tienes toda la gestión de las excepciones en un solo punto.

El problema lo tenemos a la hora de hacer los test unitarios y de integración con JUNIT ya que no se lleva nada bien el tema de que los servicios sobre los que hacemos los test. Los casos de uso que tenemos son los siguientes:

1 - Creación y ejecución de los test en Eclipse. En este caso los test pasan correctamente



2 - Ejecución de los test en Jenkins a través de un scripts (maven o ant) de compilación y ejecución de los test.

En este caso es donde nos encontramos con el problema de que la solución de la utilización de Aspecj para la gestión de excepciones no funciona porque nos devuelve el siguiente error.


--

java.lang.IllegalStateException: Failed to load ApplicationContext
 at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
 at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
 at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
 at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
 at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
 at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor#0': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer$AmbiguousBindingException: Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:452)
 at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
 at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:740)
 at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:449)
 at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103)
 at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
 at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228)
 at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
 at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
Caused by: org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer$AmbiguousBindingException: Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them
 at org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.maybeBindThisOrTargetOrArgsFromPointcutExpression(AspectJAdviceParameterNameDiscoverer.java:519)
 at org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.getParameterNames(AspectJAdviceParameterNameDiscoverer.java:264)
 at org.springframework.core.PrioritizedParameterNameDiscoverer.getParameterNames(PrioritizedParameterNameDiscoverer.java:54)
 at org.springframework.aop.aspectj.AbstractAspectJAdvice.bindArgumentsByName(AbstractAspectJAdvice.java:420)
 at org.springframework.aop.aspectj.AbstractAspectJAdvice.calculateArgumentBindings(AbstractAspectJAdvice.java:375)
 at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvice(ReflectiveAspectJAdvisorFactory.java:218)
 at org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl.instantiateAdvice(InstantiationModelAwarePointcutAdvisorImpl.java:140)
 at org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl.<init>(InstantiationModelAwarePointcutAdvisorImpl.java:89)
 at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisor(ReflectiveAspectJAdvisorFactory.java:134)
 at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory$1.doWith(ReflectiveAspectJAdvisorFactory.java:74)
 at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:473)
 at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:451)
 at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisors(ReflectiveAspectJAdvisorFactory.java:70)
 at org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors(BeanFactoryAspectJAdvisorsBuilder.java:109)
 at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:86)
 at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:107)
 at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:278)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:880)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:852)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:446)


--

La solución a este problema consiste en añadir un parámetro en la compilación de las clases en el script que se encarga de compilar las clases. El parámetro añadir es el siguiente: -g:vars

Os pongo el ejemplo de como lo añado en mi script donde todas mis clases están en las carpetas src y javatest

--
<path id="lib.path.ref">
      <fileset dir="../WebContent/WEB-INF/lib" includes="*.jar"/>
   <fileset dir="./libs" includes="*.jar"/>
</path>
<javac srcdir="../src:../javatest"
          destdir="${DirectorioBase}/WEB-INF/classes"
          classpathref="lib.path.ref"
          debug="off"
          source="1.7"
          optimize="true"
          target="1.7"
          fork="true"
   encoding="UTF8"
          includeantruntime="true">
    
                 <compilerarg value="-g:vars"/>  <!--Argumento especial para la compilación de AspectJ -->
</javac>
--

Con esto el error desaparece completamente.

Referencias:

Referencia 1 - SpringSource

Referencia 2 - epubbud





viernes, 17 de mayo de 2013

SpringData MondoDb: Configuración de conexiones PRODUCCION

Establecemos los valores de la conexión de SpringData para MongoDb en producción basándonos en el siguiente artículo encontrado en StackOverflow: How to configure MongoDB Java driver MongoOptions for production use?

auto-connect-retry="true" : para que el servidor se reconecte se pierde la conexión.

connections-per-host="40"  :  Conexiones que tendrá nuestra aplicación, son la que va a establecer del driver de java para esta aplicación.

connectTimeout = "30000": El el tiempo que espera el servidor antes de abortar un intento de conexión con la base de datos. O sea es el tiempo que espera para conseguir una conexión libre. Debe de ser algo grande entre 15 y 30 segundos para que sea realista según recomiendan.

socketTimeout="60000" : Una vez iniciada un operación de lectura, es tiempo que el socket va  a esperar la respuesta, si se supera podremos tener errores del tipo:

--
Caused by: com.mongodb.MongoException$Network: can't say something
 at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:194)
 at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:155)
 at com.mongodb.DBApiLayer$MyCollection.update(DBApiLayer.java:349)
 at com.mongodb.DBCollection.update(DBCollection.java:177)
 at com.mongodb.DBCollection.save(DBCollection.java:817)
 at com.mongodb.DBCollection.save(DBCollection.java:785)
 at org.springframework.data.mongodb.core.MongoTemplate$10.doInCollection(MongoTemplate.java:885)
 at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:388)

Caused by: java.net.SocketTimeoutException: Read timed out
 at java.net.SocketInputStream.socketRead0(Native Method)
 at java.net.SocketInputStream.read(SocketInputStream.java:150)
 at java.net.SocketInputStream.read(SocketInputStream.java:121)
 at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
 at java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
 at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
 at org.bson.io.Bits.readFully(Bits.java:46)
--

Referencia útil: connectionTimeout VS SocketTimeout

maxWaitTime = "1500" : Milisegundos que un hilo esperará  para conseguir una conexión libre del pool de conexiones.

Aquí os dejo la configuración que por ahora nos funciona correctamente.
--
<mongo:mongo host="xxx.xxx.xxx" port="xx" id="mongo">
   <mongo:options connections-per-host="40"
            threads-allowed-to-block-for-connection-multiplier="1500"
            connect-timeout="30000"
            max-wait-time="1500"
            auto-connect-retry="true"
            socket-keep-alive="true"
            socket-timeout="60000"
            slave-ok="true"
            write-number="1"
            write-timeout="0"
            write-fsync="true"/>
</mongo:mongo>

--

jueves, 21 de febrero de 2013

Configuración de Log4j para un proyecto WEB con un archivo de properties

Log4j web Project configuration

El post de hoy surge por la necesidad de configurar correctamente los logs que salen por consola en nuestros proyectos WEB.

Se acabó el utilizar el el System.out.println.



La configuración es muy variada:

1 - Configuración por programación: Desde un public void Main:
2 - Configuración desde un XML
3 - Configuración desde un archivo de properties.

pero aquí me voy a centrar en mi caso particular que es la configuración de log4j en un proyecto WEB a través de un archivo de properties.

1 - Lo primero que necesitamos tener es la última versión de nuestra librería favorita log4j.

2 - Configuramos un proyecto WEB en nuestro IDE favorito, eclipse en mi caso.

3 - Ponemos la librería (log4j-1.2.17.jar) en el directorio WEB-INF/lib

4 - Creamos y configuramos un servlet para poder realizar las pruebas, en mi caso con Spring Framework.

Una vez que tenemos el proyecto correctamente configurado vamos a lo que nos interesa

5 - Creamos el archivo log4j.properties en el raíz del directorio src para que esté en la raíz de nuestras clases, con la siguiente configuración

--
# log4j.properties for 

# Set root category priority to DEBUG and its only appender to Console.
log4j.rootLogger=debug,stdout


#appender definition
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= linea %L %c %d %m  %n

--

Con estos pasos ya sería suficiente para que aparecieran trazas pero vamos a ver como configurar, pero vamos a entender un poco como funciona.

Tenemos que diferencias entre loggers, appenders y layouts

Un logger es el elemento que se encarga de recopilar y generar los logs en base a una configuración de un appender y un patternlayout. En nuestro ejemplo el logger es stdout

Un appender es donde se almacenan los logs generados por los loggers, hay muchos tipos lo más usados el org.apache.log4j.ConsoleAppender para mostrarlo por consola. Para ampliar información en las referencias hay un montón de tipos.

Un layout es la manera en que se imprime la traza, es decir que información escribirá el logger en el appender.

El rootLogger = Es el padre de todos los appenders y la cong

Con el código que hemos puesto en la clase log4jtest.java y con la configuración de log4j.properties en debug nuestras trazas que aparecerían en la consola serian las siguientes:


linea 22 org.antuansoft.mvc.log4jtest 2013-02-16 02:48:15,057 debug
linea 23 org.antuansoft.mvc.log4jtest 2013-02-16 02:48:15,058 error
linea 24 org.antuansoft.mvc.log4jtest 2013-02-16 02:48:15,058 info
linea 25 org.antuansoft.mvc.log4jtest 2013-02-16 02:48:15,058 fatal
linea 26 org.antuansoft.mvc.log4jtest 2013-02-16 02:48:15,058 trace  Esta no debe de salir

Modificando la línea:


log4j.rootLogger=debug,stdout

podemos modificar el nivel de nuestros logs para que aparezcan o no las trazas que queremos.




Si pongo

log4j.rootLogger=error,stdout

al configurarlo para que salgan las trazas de error, las dos únicas líneas que aparecerían serían:



linea 24 org.antuansoft.mvc.log4jtest 2013-02-16 02:48:15,058 info
linea 25 org.antuansoft.mvc.log4jtest 2013-02-16 02:48:15,058 fatal


UPDATE:

Si lo que quieres es modificar el nivel de log de uno de los paquetes de tu proyecto nada más, lo que tienes que hacer es añadir la siguiente línea al log4j.properties

log4j.category.com.mypackage=LEVEL
Por ejemplo:
log4j.category.org.antuansoft.mvc=info
Eso haría que sólo las trazas que contengan ese paquete se muestren en modo info y el resto en el modo que hayamos especificado el rootlogger.



Aquí dejo un enlace con el de código y información ampliada  en los enlaces.

Código en githup, ejemplo MVC con SpringFramework y log4j

Para acceder sólo hay que ponerlo en un servidor de aplicaciones tomcat y ejecutar la siguiente url

http://localhost:8080/AntuanSoft_BASE_WEB_SPRING_PROJECT/log4jtest





Referencias: Para más información este tutorial cubre todos los casos http://www.javatutoriales.com/2011/04/log4j-para-creacion-de-eventos-de-log.html
http://www.arquitecturajava.com/log4j-y-pattern-layouts/
http://stackoverflow.com/questions/1725958/how-do-you-change-a-packages-log-level-using-log4j

miércoles, 4 de julio de 2012

Spring Data Mongodb Configurando WriteResultChecking Policy para lanzar excepciones

Setting WriteResultChecking Policy in order to throw Exceptions

Cuando trabajamos con Mongodb a la hora de hacer Queries debemos de comprobar el objeto WriteResult resultante para comprobar que la operación se ha realizado correctamente.


WriteResult wr = mongoOperations.updateFirst(
 new Query(where("id").is("objectId")),   
 new Update().push("favouriteUsers", idUser),Course.class);
  
 String error = wr.getError();




Para que no tengmos que hacer esto y si ocurre algún problema se lance una excepcion debemos de configurar Spring Data Mongo Db de la siguiente manera.

<mongo:mongo host="localhost" port="27017" id="mongo">
         <mongo:options connections-per-host="8"
                    threads-allowed-to-block-for-connection-multiplier="4"
                    connect-timeout="1000"
                    max-wait-time="1500"
                    auto-connect-retry="true"
                    socket-keep-alive="true"
                    socket-timeout="1500"
                    slave-ok="true"
                    write-number="1"
                    write-timeout="0"
                    write-fsync="true"/>
    </mongo:mongo>

 <mongo:repositories base-package="xx.xxxx.xxx"/>

 <mongo:db-factory dbname="database" mongo-ref="mongo" id="mongoDbFactory"/>
 
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    <property name="writeResultChecking" value="EXCEPTION"/>
<!-- propiedad usada para que si hay error devuelva una excepción y no haya que comprobarlo -->    
 </bean>


La clave está en la propiedad writeResultChecking que puede configurar con los valores NONE, LOG y EXCEPTION que es el caso que nos interesa.

Referencias:

Spring data mongo de documentacion

Ejemplo de configuración

lunes, 18 de junio de 2012

Spring JPA MongoDB: java.lang.NoSuchMethodError: com.mysema.query.mongodb.MongodbQuery

En nuestros proyecto estamos estamos trabajando con Spring Data Jpa para MySql y para MongoDb.

Al hora de hacer una query en MongoDb utilizando QueryDSL para utilizar los predicado que facilitan la creación de queries, nos ha dado el siguiente error.


------
java.lang.NoSuchMethodError: com.mysema.query.mongodb.MongodbQuery.<init>(Lcom/mongodb/DBCollection;Lcom/google/common/base/Function;Lcom/mysema/query/mongodb/MongodbSerializer;)V
 at org.springframework.data.mongodb.repository.support.SpringDataMongodbQuery.<init>(SpringDataMongodbQuery.java:58)
 at org.springframework.data.mongodb.repository.support.SpringDataMongodbQuery.<init>(SpringDataMongodbQuery.java:44)
 at org.springframework.data.mongodb.repository.support.QueryDslMongoRepository.createQueryFor(QueryDslMongoRepository.java:167)
 at org.springframework.data.mongodb.repository.support.QueryDslMongoRepository.count(QueryDslMongoRepository.java:154)
 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:601)
 at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
 at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
----- 
El código utilizado el el siguiente:

 
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;

import charris.example.domain.Product;

public interface ProductRepository extends MongoRepository<Product, String>, QueryDslPredicateExecutor<Product> {

}



El error proviene al hacer una query como esta:

 
ProductRepository repo = context.getBean(ProductRepository.class);
Product p = repo.findOne(QProduct.product.name.eq("ProductName"));



El problema consistía en un problema de versiones entre los jar de
  1. querydl-mongodb
  2. spring-data
El error se solucionó poniendo las versiones  adecuadas de los JAR. Nosotros tuvimos que recurrir a los Nightly builds de spring data para que funcionara perfectamente.

Las versiones de los Jars fueron las siguientes a fecha (18/06/2012)

  •  querydsl-mongodb-2.5.0.jar
  • querydsl-mongodb-2.5.0-apt.jar
  • querydsl-mongodb-2.5.0-apt-one-jar.jar
  • spring-data-commons-core-1.3.2.BUILD-20120618.140513-1.jar
  • spring-data-jpa-1.1.1.BUILD-20120606.192912-1.jar
  • spring-data-mongodb-1.1.0.BUILD-20120614.104654-40.jar