DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

The Latest Frameworks Topics

article thumbnail
Creating a Copy of JavaBeans
In this post, we shall see how to make a copy of an object in Java. In our applications, JavaBeans play a very important role. However sometimes we simply need to make a copy of our JavaBeans so as to make changes to the copy and keep the original object intact. There are two ways in which this can be achieved in Java, depending upon the level of access you have to your beans. Using Object.clone() Using BeanUtils Copying using Object.clone() This method can be used when you have access to the source code of your bean classes. This method requires your JavaBeans to implement the cloneable interface. The Cloneable interface is a marker interface that indicates that the object allows itself to be cloned. We can call the Object.clone() method on only on objects whose classes implement the Cloneable interface. If we attempt to invoke the clone() method on an object of a class that does not implement the Cloneable interface, we get a CloneNotSupportedException. Also note that the clone() method is a protected method, so you will most likely need to create a public method on your bean class named clone() to mimic the functionality. We are going to demonstrate both the above methods using a simple Employee class. This class will contain an instance of another javabean 'Address'. We shall see in the below example, how we can obtain a deep copy of our beans. The following code demonstrates the usage of Object.clone() Address.java class Address { private int houseNo; public int getHouseNo() { return houseNo; } public void setHouseNo(int houseNo) { this.houseNo = houseNo; } @Override public String toString() { return "houseNo : " + houseNo; } } Employee.java class Employee implements Cloneable { private String name = null; private Address address=null; @Override public String toString() { return "name " + this.getName()+ " address : "+ address; } public Employee clone() { Employee emp = null; try { emp = (Employee) super.clone(); } catch (CloneNotSupportedException e) { System.out.println(e); } return emp; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } } Note that in the above classes, the Employee class and the Address class is declared with a visibility of default. We did not have to make them public, although we could have. Also note the way the clone() method has been written in the Employee class. I explicitly declared it as as a public method and called the superclass implementation of the clone method. Then, I downcasted it to am Employee object before returning. Lets see the code in action. public static void main(String[] args) { Employee emp1 = new Employee(); Address add1= new Address(); add1.setHouseNo(100); emp1.setName("ryan"); emp1.setAddress(add1); Employee emp2 = emp1.clone(); emp2.setName("ryan2"); print("emp1 : " + emp1); print("emp2 : " + emp2); print("emp1==emp2 "+(emp1==emp2)); } If you execute the following code, you will get the below output emp1 : name ryan address : houseNo : 100 emp2 : name ryan2 address : houseNo : 100 emp1==emp2 false You can replace the print statement with your logger statement to run the code. Note that the == operator indicates that both the objects are created independently on the heap. Moreover, the fields of the Address bean have also been copied. One crucial thing to be noted here is that you only needed to implement the Cloneable interface in the Employee class. The Address class does not need to implement Cloneable, although there wont be any serious repercussions if you do so! Now lets see the second method Using the BeanUtils.cloneBean() class This method makes use of the BeanUtils class provided by the apache foundation. In order to use this class, you need to have at least the following jar files in your classpath commons-beanutils-1.7.0.jar commons-collections-3.1.jar commons-logging-1.0.4.jar The version numbers may differ, but you can get the details from the here if the dependencies change. The BeanUtils class provides us a method called cloneBean that clones all the accessible properties of your beans. Here is the code in Action. Employee2.class public class Employee2{ private String name = null; private Address address=null; @Override public String toString() { return "name " + this.getName()+ " address : "+ address; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } } Note the declaration of the Employee2 class. We did not implement the Cloneable interface. Moreover, we made the class "public". Making the class public is required for the BeanUtils class to extract the data from the Bean. Also note that we did not have to write a clone() function in this class. We can reuse the existing Address class from the previous example, as no changes need to be done to it. You need to import the following line in your main class import org.apache.commons.beanutils.BeanUtils; Now lets take a look at the main function. public static void main(String[] args) throws Exception{ BeanUtils bu = new BeanUtils(); Employee2 emp1 = new Employee2(); Address add1= new Address(); add1.setHouseNo(100); emp1.setName("ryan"); emp1.setAddress(add1); Employee2 emp2 = (Employee2)bu.cloneBean(emp1); emp2.setName("??"); print(emp1); print(emp2); print("emp1==emp2 : "+(emp1==emp2)); } As you see above, we did not have to do much but simply call the cloneBean method on the BeanUtils object and downcast it to our Employee2 bean. As was expected, a deep copy of the object was created. If you run the code, you get the following output name ryan address : houseNo : 100 name ?? address : houseNo : 100 emp1==emp2 : false As expected, both the objects are considered to be different objects on the heap. They just have the same values for their properties. In the methods discussed above, you can see that the BeanUtils method can be used in a much wider scope because most of your JavaBeans will be public, but you may not always have access to the code of your JavaBeans to write a clone method. Thats all for now folks! Happy Programming :) From http://mycodefixes.blogspot.com/2011/02/creating-deep-copy-of-javabeans.html
February 28, 2011
by Ryan Sukale
· 25,598 Views
article thumbnail
Implementing Ajax Authentication using jQuery, Spring Security and HTTPS
I've always had a keen interest in implementing security in webapps. I implemented container-managed authentication (CMA) in AppFuse in 2002, watched Tomcat improve it's implementation in 2003 and implemented Remember Me with CMA in 2004. In 2005, I switched from CMA to Acegi Security (now Spring Security) and never looked back. I've been very happy with Spring Security over the years, but also hope to learn more about Apache Shiro and implementing OAuth to protect JavaScript APIs in the near future. I was recently re-inspired to learn more about security when working on a new feature at Overstock.com. The feature hasn't been released yet, but basically boils down to allowing users to login without leaving a page. For example, if they want to leave a review on a product, they would click a link, be prompted to login, enter their credentials, then continue to leave their review. The login prompt and subsequent review would likely be implemented using a lightbox. While lightboxes are often seen in webapps these days because they look good, it's also possible Lightbox UIs provide a poor user experience. User experience aside, I think it's interesting to see what's required to implement such a feature. To demonstrate how we did it, I whipped up an example using AppFuse Light, jQuery and Spring Security. The source is available in my ajax-login project on GitHub. To begin, I wanted to accomplish a number of things to replicate the Overstock environment: Force HTTPS for authentication. Allow testing HTTPS without installing a certificate locally. Implement a RESTful LoginService that allows users to login. Implement login with Ajax, with the request coming from an insecure page. Forcing HTTPS with Spring Security The first feature was fairly easy to implement thanks to Spring Security. Its configuration supports a requires-channel attribute that can be used for this. I used this to force HTTPS on the "users" page and it subsequently causes the login to be secure. Testing HTTPS without adding a certificate locally After making the above change in security.xml, I had to modify my jWebUnit test to work with SSL. In reality, I didn't have to modify the test, I just had to modify the configuration that ran the test. In my last post, I wrote about adding my 'untrusted' cert to my JVM keystore. For some reason, this works for HttpClient, but not for jWebUnit/HtmlUnit. The good news is I figured out an easier solution - adding the trustStore and trustStore password as system properties to the maven-failsafe-plugin configuration. maven-failsafe-plugin 2.7.2 **/*WebTest.java ${project.build.directory}/ssl.keystore appfuse The disadvantage to doing things this way is you'll have to pass these in as arguments when running unit tests in your IDE. Implementing a LoginService Next, I set about implementing a LoginService as a Spring MVC Controller that returns JSON thanks to the @ResponseBody annotation and Jackson. package org.appfuse.examples.web; import org.appfuse.model.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/api/login.json") public class LoginService { @Autowired @Qualifier("authenticationManager") AuthenticationManager authenticationManager; @RequestMapping(method = RequestMethod.GET) @ResponseBody public LoginStatus getStatus() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && !auth.getName().equals("anonymousUser") && auth.isAuthenticated()) { return new LoginStatus(true, auth.getName()); } else { return new LoginStatus(false, null); } } @RequestMapping(method = RequestMethod.POST) @ResponseBody public LoginStatus login(@RequestParam("j_username") String username, @RequestParam("j_password") String password) { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); User details = new User(username); token.setDetails(details); try { Authentication auth = authenticationManager.authenticate(token); SecurityContextHolder.getContext().setAuthentication(auth); return new LoginStatus(auth.isAuthenticated(), auth.getName()); } catch (BadCredentialsException e) { return new LoginStatus(false, null); } } public class LoginStatus { private final boolean loggedIn; private final String username; public LoginStatus(boolean loggedIn, String username) { this.loggedIn = loggedIn; this.username = username; } public boolean isLoggedIn() { return loggedIn; } public String getUsername() { return username; } } } To verify this class worked as expected, I wrote a unit test using JUnit and Mockito. I used Mockito because Overstock is transitioning to it from EasyMock and I've found it very simple to use. package org.appfuse.examples.web; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Matchers; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextImpl; import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class LoginServiceTest { LoginService loginService; AuthenticationManager authenticationManager; @Before public void before() { loginService = new LoginService(); authenticationManager = mock(AuthenticationManager.class); loginService.authenticationManager = authenticationManager; } @After public void after() { SecurityContextHolder.clearContext(); } @Test public void testLoginStatusSuccess() { Authentication auth = new TestingAuthenticationToken("foo", "bar"); auth.setAuthenticated(true); SecurityContext context = new SecurityContextImpl(); context.setAuthentication(auth); SecurityContextHolder.setContext(context); LoginService.LoginStatus status = loginService.getStatus(); assertTrue(status.isLoggedIn()); } @Test public void testLoginStatusFailure() { LoginService.LoginStatus status = loginService.getStatus(); assertFalse(status.isLoggedIn()); } @Test public void testGoodLogin() { Authentication auth = new TestingAuthenticationToken("foo", "bar"); auth.setAuthenticated(true); when(authenticationManager.authenticate(Matchers.anyObject())).thenReturn(auth); LoginService.LoginStatus status = loginService.login("foo", "bar"); assertTrue(status.isLoggedIn()); assertEquals("foo", status.getUsername()); } @Test public void testBadLogin() { Authentication auth = new TestingAuthenticationToken("foo", "bar"); auth.setAuthenticated(false); when(authenticationManager.authenticate(Matchers.anyObject())) .thenThrow(new BadCredentialsException("Bad Credentials")); LoginService.LoginStatus status = loginService.login("foo", "bar"); assertFalse(status.isLoggedIn()); assertEquals(null, status.getUsername()); } } Implement login with Ajax The last feature was the hardest to implement and still isn't fully working as I'd hoped. I used jQuery and jQuery UI to implement a dialog that opens the login page on the same page rather than redirecting to the login page. The "#demo" locator refers to a button in the page. Passing in the "ajax=true" parameter disables SiteMesh decoration on the login page, something that's described in my Ajaxified Body article. var dialog = $(''); $(document).ready(function() { $.get('/login?ajax=true', function(data) { dialog.html(data); dialog.dialog({ autoOpen: false, title: 'Authentication Required' }); }); $('#demo').click(function() { dialog.dialog('open'); // prevent the default action, e.g., following a link return false; }); }); Instead of adding a click handler to a specific id, it's probably better to use a CSS class that indicates authentication is required for a link, or -- even better -- use Ajax to see if the link is secured. The login page then has the following JavaScript to add a click handler to the "login" button that submits the request securely to the LoginService. var getHost = function() { var port = (window.location.port == "8080") ? ":8443" : ""; return ((secure) ? 'https://' : 'http://') + window.location.hostname + port; }; var loginFailed = function(data, status) { $(".error").remove(); $('#username-label').before('Login failed, please try again.'); }; $("#login").live('click', function(e) { e.preventDefault(); $.ajax({url: getHost() + "/api/login.json", type: "POST", data: $("#loginForm").serialize(), success: function(data, status) { if (data.loggedIn) { // success dialog.dialog('close'); location.href= getHost() + '/users'; } else { loginFailed(data); } }, error: loginFailed }); }); The biggest secret to making this all work (the HTTP -> HTTPS communication, which is considered cross-domain), is the window.name Transport and the jQuery plugin that implements it. To make this plugin work with Firefox 3.6, I had to implement a Filter that adds Access-Control headers. A question on Stackoverflow helped me figure this out. public class OptionsHeadersFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET,POST"); response.setHeader("Access-Control-Max-Age", "360"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); chain.doFilter(req, res); } public void init(FilterConfig filterConfig) { } public void destroy() { } } Issues I encountered a number of issues when implementing this in the ajax-login project. If you try to run this with ports (e.g. 8080 and 8443) in your URLs, you'll get a 501 (Not Implemented) response. Removing the ports by fronting with Apache and mod_proxy solves this problem. If you haven't accepted the certificate in your browser, the Ajax request will fail. In the example, I solved this by clicking on the "Users" tab to make a secure request, then going back to the homepage to try and login. The jQuery window.name version 0.9.1 doesn't work with jQuery 1.5.0. The error is "$.httpSuccess function not found." Finally, even though I was able to authenticate successfully, I was unable to make the authentication persist. I tried adding the following to persist the updated SecurityContext to the session, but it doesn't work. I expect the solution is to create a secure JSESSIONID cookie somehow. @Autowired SecurityContextRepository repository; @RequestMapping(method = RequestMethod.POST) @ResponseBody public LoginStatus login(@RequestParam("j_username") String username, @RequestParam("j_password") String password, HttpServletRequest request, HttpServletResponse response) { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); ... try { Authentication auth = authenticationManager.authenticate(token); SecurityContextHolder.getContext().setAuthentication(auth); // save the updated context to the session repository.saveContext(SecurityContextHolder.getContext(), request, response); return new LoginStatus(auth.isAuthenticated(), auth.getName()); } catch (BadCredentialsException e) { return new LoginStatus(false, null); } } Conclusion This article has shown you how to force HTTPS for login, how to do integration testing with a self-generated certificate, how to implement a LoginService with Spring MVC and Spring Security, as well as how to use jQuery to talk to a service cross-domain with the window.name Transport. While I don't have everything working as much as I'd like, I hope this helps you implement a similar feature in your applications. One thing to be aware of is with lightbox/dialog logins and HTTP -> HTTPS is that users won't see a secure icon in their address bar. If your app has sensitive data, you might want to force https for your entire app. OWASP's Secure Login Pages has a lot of good tips in this area. Update: I've posted a demo of the ajax-login webapp. Thanks to Contegix for hosting the demo and helping obtain/install an SSL certificate so quickly. Update March 24, 2011: Rob Winch figured out how to make this work and sent me a patch. From his comment: The first issue is that Access-Control-Allow-Credentials header must be set to true. This is so that the browser knows it can send and accept cookies. The second issue is that XMLHttpRequest.withCredentials should be set to true. The last change was that in order to allow credentials to work across domains, the Access-Control-Allow-Origin must be a specific value (i.e. it won't work if you use a wildcard). For more information, you can read about it on mozilla's site. I've updated the demo with these changes. Works great now - thanks Rob! From http://raibledesigns.com/rd/entry/implementing_ajax_authentication_using_jquery
February 24, 2011
by Matt Raible
· 89,634 Views
article thumbnail
Spring and Hibernate Application with Zero XML
The Spring framework came up with annotation support since 2.5 version which eases development. Whether the annotation based approach, or XML approach is better, is depends on the project and your personal preference. Let us see how we can write a Simple Application using Spring and Hibernate using annotations, no xml at all. The configuration for JDBC datasource and Hibernate properties: application.properties ################### JDBC Configuration ########################## jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:file:db/SivaLabsDB;shutdown=true jdbc.username=sa jdbc.password= ################### Hibernate Configuration ########################## hibernate.dialect=org.hibernate.dialect.HSQLDialect hibernate.show_sql=true hibernate.hbm2ddl.auto=update hibernate.generate_statistics=true We can instantiate ApplicationContext from a Java file using the @Configuration annotation. AppConfig.java package com.sivalabs.springmvc.config; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.io.ClassPathResource; /** * @author SivaLabs * */ @Import({RepositoryConfig.class}) @Configuration public class AppConfig { // @Bean public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer() { PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); ppc.setLocation(new ClassPathResource("application.properties")); ppc.setIgnoreUnresolvablePlaceholders(true); return ppc; } } Here @Import({RepositoryConfig.class}) is the same as the xml version: package com.sivalabs.springmvc.config; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.sql.DataSource; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.orm.hibernate3.HibernateTransactionManager; import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean; import org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener; import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionInterceptor; /** * @author SivaLabs * */ @Configuration public class RepositoryConfig { //${jdbc.driverClassName} @Value("${jdbc.driverClassName}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Value("${hibernate.dialect}") private String hibernateDialect; @Value("${hibernate.show_sql}") private String hibernateShowSql; @Value("${hibernate.hbm2ddl.auto}") private String hibernateHbm2ddlAuto; @Bean() public DataSource getDataSource() { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName(driverClassName); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); return ds; } @Bean @Autowired public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) { HibernateTransactionManager htm = new HibernateTransactionManager(); htm.setSessionFactory(sessionFactory); return htm; } @Bean @Autowired public HibernateTemplate getHibernateTemplate(SessionFactory sessionFactory) { HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory); return hibernateTemplate; } @Bean public AnnotationSessionFactoryBean getSessionFactory() { AnnotationSessionFactoryBean asfb = new AnnotationSessionFactoryBean(); asfb.setDataSource(getDataSource()); asfb.setHibernateProperties(getHibernateProperties()); asfb.setPackagesToScan(new String[]{"com.sivalabs"}); return asfb; } @Bean public Properties getHibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect", hibernateDialect); properties.put("hibernate.show_sql", hibernateShowSql); properties.put("hibernate.hbm2ddl.auto", hibernateHbm2ddlAuto); return properties; } } Create an Entity User as follows: package com.sivalabs.springmvc.entities; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; /** * @author SivaLabs * */ @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; private String address; public User() { } public User(Integer id, String name, String address) { this.id = id; this.name = name; this.address = address; } @Override public String toString() { return "User [address=" + address + ", id=" + id + ", name=" + name+ "]"; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } Create UserRepository to perform DB operations using Hibernate. package com.sivalabs.springmvc.repositories; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.sivalabs.springmvc.entities.User; /** * @author SivaLabs * */ @Transactional @Repository public class UserRepository { @Autowired private HibernateTemplate hibernateTemplate; public List getAllUsers() { return this.hibernateTemplate.loadAll(User.class); } public Integer createUser(User user) { User mergeUser = this.hibernateTemplate.merge(user); return mergeUser.getId(); } } Create a UserService class which is responsible for performing User operations. package com.sivalabs.springmvc.services; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.sivalabs.springmvc.entities.User; import com.sivalabs.springmvc.repositories.UserRepository; /** * @author SivaLabs * */ @Service public class UserService { @Autowired private UserRepository userRepository; public List getAllUsers() { return this.userRepository.getAllUsers(); } public Integer createUser(User user) { return this.userRepository.createUser(user); } } Now let us create ApplicationContext from AppConfig.java and test the functionality. package com.sivalabs.test; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.sivalabs.springmvc.entities.User; import com.sivalabs.springmvc.services.UserService; public class ContainerTest { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.scan("com.sivalabs");//This will load the configured components UserService, UserRepository, ctx.refresh(); System.out.println(ctx); UserService userService = ctx.getBean("userService", UserService.class); List allUser = userService.getAllUsers(); for (User u : allUser) { System.out.println(u); } User user = new User(null, "K.siva reddy", "hyderabad"); Integer id = userService.createUser(user); System.out.println("Newly created User Id="+id); allUser = userService.getAllUsers(); for (User u : allUser) { System.out.println(u); } } } See how application development is much more easier now with Annotations. From : http://sivalabs.blogspot.com/2011/02/springhibernate-application-with-zero.html
February 23, 2011
by Siva Prasad Reddy Katamreddy
· 75,452 Views · 7 Likes
article thumbnail
The Easiest Ways to Navigate Methods in a Class using Eclipse Keyboard Shortcuts
java classes can get big and hairy, making it difficult to find the method you’re looking for when browsing or editing a class. there is no specific order to where methods can be in a class and different developers have different preferences about where to put them. you could use the mouse wheel and scroll ferociously until you eventually find the method or you could even use page down/page up on your keyboard. but these methods can be time-consuming and haphazard, especially when the class has lots of methods or they’re scattered in an arbitrary order. luckily, eclipse has a number of fast and easy ways to help you navigate methods in a class, especially using the keyboard. i’ll discuss some of those keyboard shortcuts and also which ones to use when. quick outline the quick outline is basically a scaled-down popup version of the outline view. the main advantage over the outline view is that it has a search box that allows you to search for a method. here’s how to use the quick outline: press ctrl+o from anywhere within the class. type a search term in the search box and eclipse will just show all methods that match the search term. by default eclipse does an exact match search, but you can use wildcards. once you see the method you’re interested in, press down to select the method (if it’s not selected already). press enter once the method is selected. eclipse will take you directly to the method’s declaration. this is an example of the popup for java’s arraylist . searching for *rem will search for all method names that contain the word rem . here’s an example: notes: sort the view using the the down arrow menu in the top right corner. it makes it easier to find methods by scanning. resize the quick outline popup to see more methods. eclipse remembers the size of the popup for the next time you open it. next member & previous member another way to move between methods is to use two features called go to next member and go to previous member. when you press ctrl+shift+down , eclipse moves the cursor to the next method in the class. pressing ctrl+shift+up moves to the previous method. here’s a video to give you a quick example of how these shortcuts work: this shortcut works best if you’re already positioned in a method or if the class has few fields. that’s because to eclipse a member can either be a method or a field. if you’re at the top of the class, you have to move through all the fields before you actually start moving through the methods themselves, a time-consuming process especially for bigger classes with lots of fields. it helps to generate getters and setters at the bottom of the class because you don’t have to navigate through them to get to the useful methods. open declaration if you’ve got lots of private methods in your class then open declaration might be the best way to navigate between them. when you’re positioned on a method call and press f3 , eclipse takes you directly to the definition of that method. for example, if you’re busy in the method process() and your cursor’s positioned on initprocessing() , pressing f3 will take you directly to the declaration for that method further down the class. public void process() { //do things... initprocessing(); //... } ... private void initprocessing() { //init something... } this feature works very well with alt+left (backward history). see the section below for more details about the backward history. navigating back to a previously viewed method while browsing code, you’ll often want to return to the previous method you were viewing once you’re done viewing the method it calls. to do this, use alt+left (backward history) to move back to the last navigation point. this feature isn’t specific to just methods, but also works for navigating between previously visited editors. but it works great if you’ve just been browsing methods within a class. quick mentions eclipse’s outline view also allows easy navigation but mostly with the mouse. you could navigate to the view using alt+shift+q, o , and you can move to methods by typing their first letter, but i’ve found the quick outline to be more keyboard friendly. also, the outline view doesn’t support wildcard searches. you can also use eclipse’s call hierarchy ( ctrl+alt+h ) especially if you’re trying to understand the flow of methods in a class and move between them easily. knowing how to navigate between views and editors with the keyboard helps a lot since you’ll be moving between the call hierarchy view and editors a lot. what should i use when? use next/previous member shortcut if the class is small or you have a good idea of where other methods are in relation to the current method (eg. are they above/below the current method). use the quick outline if you don’t know the class too well or there are lots of methods in the class. use open declaration if you’re moving between many private methods of the class. it’s normally the fastest way to move to another private method in the class, but only if you’re already positioned in a method that calls it. from http://eclipseone.wordpress.com/2011/02/21/the-easiest-ways-to-navigate-methods-in-a-class-using-eclipse-keyboard-shortcuts/
February 22, 2011
by Byron M
· 66,970 Views · 2 Likes
article thumbnail
Table sorting & pagination with jQuery and Razor in ASP.NET MVC
Introduction jQuery enjoys living inside pages which are built on top of ASP.NET MVC Framework. The ASP.NET MVC is a place where things are organized very well and it is quite hard to make them dirty, especially because the pattern enforces you on purity (you can still make it dirty if you want so ;) ). We all know how easy is to build a HTML table with a header row, footer row and table rows showing some data. With ASP.NET MVC we can do this pretty easy, but, the result will be pure HTML table which only shows data, but does not includes sorting, pagination or some other advanced features that we were used to have in the ASP.NET WebForms GridView. Ok, there is the WebGrid MVC Helper, but what if we want to make something from pure table in our own clean style? In one of my recent projects, I’ve been using the jQuery tablesorter and tablesorter.pager plugins that go along. You don’t need to know jQuery to make this work… You need to know little CSS to create nice design for your table, but of course you can use mine from the demo… So, what you will see in this blog is how to attach this plugin to your pure html table and a div for pagination and make your table with advanced sorting and pagination features. Demo Project Resources The resources I’m using for this demo project are shown in the following solution explorer window print screen: Content/images – folder that contains all the up/down arrow images, pagination buttons etc. You can freely replace them with your own, but keep the names the same if you don’t want to change anything in the CSS we will built later. Content/Site.css – The main css theme, where we will add the theme for our table too Controllers/HomeController.cs – The controller I’m using for this project Models/Person.cs – For this demo, I’m using Person.cs class Scripts – jquery-1.4.4.min.js, jquery.tablesorter.js, jquery.tablesorter.pager.js – required script to make the magic happens Views/Home/Index.cshtml – Index view (razor view engine) the other items are not important for the demo. ASP.NET MVC 1. Model In this demo I use only one Person class which defines Person entity with several properties. You can use your own model, maybe one which will access data from database or any other resource. Person.cs public class Person { public string Name { get; set; } public string Surname { get; set; } public string Email { get; set; } public int? Phone { get; set; } public DateTime? DateAdded { get; set; } public int? Age { get; set; } public Person(string name, string surname, string email, int? phone, DateTime? dateadded, int? age) { Name = name; Surname = surname; Email = email; Phone = phone; DateAdded = dateadded; Age = age; } } 2. View In our example, we have only one Index.chtml page where Razor View engine is used. Razor view engine is my favorite for ASP.NET MVC because it’s very intuitive, fluid and keeps your code clean. 3. Controller Since this is simple example with one page, we use one HomeController.cs where we have two methods, one of ActionResult type (Index) and another GetPeople() used to create and return list of people. HomeController.cs public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { ViewBag.People = GetPeople(); return View(); } public List GetPeople() { List listPeople = new List(); listPeople.Add(new Person("Hajan", "Selmani", "[email protected]", 070070070,DateTime.Now, 25)); listPeople.Add(new Person("Straight", "Dean", "[email protected]", 123456789, DateTime.Now.AddDays(-5), 35)); listPeople.Add(new Person("Karsen", "Livia", "[email protected]", 46874651, DateTime.Now.AddDays(-2), 31)); listPeople.Add(new Person("Ringer", "Anne", "[email protected]", null, DateTime.Now, null)); listPeople.Add(new Person("O'Leary", "Michael", "[email protected]", 32424344, DateTime.Now, 44)); listPeople.Add(new Person("Gringlesby", "Anne", "[email protected]", null, DateTime.Now.AddDays(-9), 18)); listPeople.Add(new Person("Locksley", "Stearns", "[email protected]", 2135345, DateTime.Now, null)); listPeople.Add(new Person("DeFrance", "Michel", "[email protected]", 235325352, DateTime.Now.AddDays(-18), null)); listPeople.Add(new Person("White", "Johnson", null, null, DateTime.Now.AddDays(-22), 55)); listPeople.Add(new Person("Panteley", "Sylvia", null, 23233223, DateTime.Now.AddDays(-1), 32)); listPeople.Add(new Person("Blotchet-Halls", "Reginald", null, 323243423, DateTime.Now, 26)); listPeople.Add(new Person("Merr", "South", "[email protected]", 3232442, DateTime.Now.AddDays(-5), 85)); listPeople.Add(new Person("MacFeather", "Stearns", "[email protected]", null, DateTime.Now, null)); return listPeople; } } TABLE CSS/HTML DESIGN Now, lets start with the implementation. First of all, lets create the table structure and the main CSS. 1. HTML Structure @{ Layout = null; } value value value So, this is the main structure you need to create for each of your tables where you want to apply the functionality we will create. Of course the scripts are referenced once ;). As you see, our table has class tablesorter and also we have a div with id pager. In the next steps we will use both these to create the needed functionalities. The complete Index.cshtml coded to get the data from controller and display in the page is: NameSurnameEmailPhoneDate Added @{ foreach (var p in ViewBag.People) { @[email protected]@[email protected]@p.DateAdded } } NameSurnameEmailPhoneDate Added 510203040 So, mainly the structure is the same. I have added @Razor code to create table with data retrieved from the ViewBag.People which has been filled with data in the home controller. 2. CSS Design The CSS code I’ve created is: /* DEMO TABLE */ body { font-size: 75%; font-family: Verdana, Tahoma, Arial, "Helvetica Neue", Helvetica, Sans-Serif; color: #232323; background-color: #fff; } table { border-spacing:0; border:1px solid gray;} table.tablesorter thead tr .header { background-image: url(images/bg.png); background-repeat: no-repeat; background-position: center right; cursor: pointer; } table.tablesorter tbody td { color: #3D3D3D; padding: 4px; background-color: #FFF; vertical-align: top; } table.tablesorter tbody tr.odd td { background-color:#F0F0F6; } table.tablesorter thead tr .headerSortUp { background-image: url(images/asc.png); } table.tablesorter thead tr .headerSortDown { background-image: url(images/desc.png); } table th { width:150px; border:1px outset gray; background-color:#3C78B5; color:White; cursor:pointer; } table thead th:hover { background-color:Yellow; color:Black;} table td { width:150px; border:1px solid gray;} PAGINATION AND SORTING Now, when everything is ready and we have the data, lets make pagination and sorting functionalities 1. jQuery Scripts referencing 2. jQuery Sorting and Pagination script So, with only two lines of code, I’m using both tablesorter and tablesorterPager plugins, giving some options to both these. Options added: tablesorter - widthFixed: true – gives fixed width of the columns tablesorter - sortList[[0,0]] – An array of instructions for per-column sorting and direction in the format: [[columnIndex, sortDirection], ... ] where columnIndex is a zero-based index for your columns left-to-right and sortDirection is 0 for Ascending and 1 for Descending. A valid argument that sorts ascending first by column 1 and then column 2 looks like: [[0,0],[1,0]] (source: http://tablesorter.com/docs/) tablesorterPager – container: $(“#pager”) – tells the pager container, the div with id pager in our case. tablesorterPager – size: the default size of each page, where I get the default value selected, so if you put selected to any other of the options in your select list, you will have this number of rows as default per page for the table too. END RESULTS 1. Table once the page is loaded (default results per page is 5 and is automatically sorted by 1st column as sortList is specified) 2. Sorted by Phone Descending 3. Changed pagination to 10 items per page 4. Sorted by Phone and Name (use SHIFT to sort on multiple columns) 5. Sorted by Date Added 6. Page 3, 5 items per page ADDITIONAL ENHANCEMENTS We can do additional enhancements to the table. We can make search for each column. I will cover this in one of my next blogs. Stay tuned. DEMO PROJECT You can download demo project source code from HERE. CONCLUSION Once you finish with the demo, run your page and open the source code. You will be amazed of the purity of your code. Working with pagination in client side can be very useful. One of the benefits is performance, but if you have thousands of rows in your tables, you will get opposite result when talking about performance. Hence, sometimes it is nice idea to make pagination on back-end. So, the compromise between both approaches would be best to combine both of them. I use at most up to 500 rows on client-side and once the user reach the last page, we can trigger ajax postback which can get the next 500 rows using server-side pagination of the same data. I would like to recommend the following blog post http://weblogs.asp.net/gunnarpeipman/archive/2010/09/14/returning-paged-results-from-repositories-using-pagedresult-lt-t-gt.aspx, which will help you understand how to return page results from repository. I hope this was helpful post for you. Wait for my next posts ;). Please do let me know your feedback. Best Regards, Hajan
February 14, 2011
by Hajan Selmani
· 77,601 Views
article thumbnail
Introduction to iBatis (MyBatis), An alternative to Hibernate and JDBC
i started to write a new article series about ibatis / mybatis . this is the first article and it will walk you through what is ibatis / mybatis and why you should use it. for those who does not know ibatis / mybatis yet, it is a persistence framework – an alternative to jdbc and hibernate , available for java and .net platforms. i’ve been working with it for almost two years, and i am enjoying it! the first thing you may notice in this and following articles about ibatis/mybatis is that i am using both ibatis and mybatis terms. why? until june 2010, ibatis was under apache license and since then, the framework founders decided to move it to google code and they renamed it to mybatis. the framework is still the same though, it just has a different name now. i gathered some resources, so i am just going to quote them: what is mybatis/ibatis? the mybatis data mapper framework makes it easier to use a relational database with object-oriented applications. mybatis couples objects with stored procedures or sql statements using a xml descriptor. simplicity is the biggest advantage of the mybatis data mapper over object relational mapping tools.to use the mybatis data mapper, you rely on your own objects, xml, and sql. there is little to learn that you don’t already know. with the mybatis data mapper, you have the full power of both sql and stored procedures at your fingertips. ( www.mybatis.org ) ibatis is based on the idea that there is value in relational databases and sql, and that it is a good idea to embrace the industrywide investment in sql. we have experiences whereby the database and even the sql itself have outlived the application source code, and even multiple versions of the source code. in some cases we have seen that an application was rewritten in a different language, but the sql and database remained largely unchanged. it is for such reasons that ibatis does not attempt to hide sql or avoid sql. it is a persistence layer framework that instead embraces sql by making it easier to work with and easier to integrate into modern object-oriented software. these days, there are rumors that databases and sql threaten our object models, but that does not have to be the case. ibatis can help to ensure that it is not. ( ibatis in action book) so… what is ibatis ? a jdbc framework developers write sql, ibatis executes it using jdbc. no more try/catch/finally/try/catch. an sql mapper automatically maps object properties to prepared statement parameters. automatically maps result sets to objects. support for getting rid of n+1 queries. a transaction manager ibatis will provide transaction management for database operations if no other transaction manager is available. ibatis will use external transaction management (spring, ejb cmt, etc.) if available. great integration with spring, but can also be used without spring (the spring folks were early supporters of ibatis). what isn’t ibatis ? an orm does not generate sql does not have a proprietary query language does not know about object identity does not transparently persist objects does not build an object cache essentially, ibatis is a very lightweight persistence solution that gives you most of the semantics of an o/r mapping toolkit, without all the drama. in other words ,ibatis strives to ease the development of data-driven applications by abstracting the low-level details involved in database communication (loading a database driver, obtaining and managing connections, managing transaction semantics, etc.), as well as providing higher-level orm capabilities (automated and configurable mapping of objects to sql calls, data type conversion management, support for static queries as well as dynamic queries based upon an object’s state, mapping of complex joins to complex object graphs, etc.). ibatis simply maps javabeans to sql statements using a very simple xml descriptor. simplicity is the key advantage of ibatis over other frameworks and object relational mapping tools.( http://www.developersbook.com ) who is using ibatis/mybatis? see the list in this link: http://www.apachebookstore.com/confluence/oss/pages/viewpage.action?pageid=25 i think the biggest case is myspace , with millions of users. very nice! this was just an introduction, so in next articles i will show how to create an application using ibatis/mybatis – step-by-step. enjoy! from http://loianegroner.com/2011/02/introduction-to-ibatis-mybatis-an-alternative-to-hibernate-and-jdbc/
February 9, 2011
by Loiane Groner
· 42,706 Views · 5 Likes
article thumbnail
Sending Beans as XML with JmsTemplate
We often want to send XML via web services. We may already have the schema or annotated JAXB2 classes configured in our application. What if we want to send the same format via JMS? By default Spring JMS is configured to send & receive objects serialized. How can we switch to using JAXB2 (or any other OXM marshaling strategy)? The following example assumes we are going from annotations first instead of from XML Schema. Quick Overview Annotate Bean with JAXB2 Configure OXM Converter Integration Test Visualize Results Logging Configuration Maven Configuration 1. Annotate Bean with JAXB2 Use JAXB2 annotations for our bean package com.gordondickens.jmswithoxm; import java.math.BigDecimal; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "account") @XmlAccessorType(XmlAccessType.FIELD) public class Account { @XmlElement(required = true) private String name; @XmlElement private String description; @XmlElement private BigDecimal balance; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public BigDecimal getBalance() { return balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } @Override public String toString() { return "Account [name=" + name + ", description=" + description + ", balance=" + balance + "]"; } } 2. Configure OXM Converter Define our Marshalers – We see defines JAXB2 as our marshaller for the Account class Register our MarshallingMessageConverter – We register the MarshallingMessageConverter to use the JAXB2 marshaller for both inbound and outbound data Register our Converter – In the JmsTemplate, we register our oxmMessageConverter as the messageConverter. This replaces the default SimpleMessageConverter which will relies on Serialization Notice the ActiveMQ namespace? 3. Integration Test Populate the Account bean Calls convertAndSend on the JmsTemplate to marshal & send the Account Includes a postProcessor callback to log the XML data Calls receiveAndConvert on the JmsTemplate to get & unmarshal the Account Asserts end state ? package com.gordondickens.jmswithoxm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.math.BigDecimal; import javax.jms.BytesMessage; import javax.jms.JMSException; import javax.jms.Message; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessagePostProcessor; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class JmsWithOxmTest { private static final Logger logger = LoggerFactory .getLogger(JunitWithOxmTest.class); private static final String TEST_DEST = "oxmTestQueue"; @Autowired JmsTemplate jmsTemplate; @Test public void testSendingMessage() { Account account = generateTestMessage(); jmsTemplate.convertAndSend(TEST_DEST, account, new MessagePostProcessor() { @Override public Message postProcessMessage(Message message) throws JMSException { if (message instanceof BytesMessage) { BytesMessage messageBody = (BytesMessage) message; // message is in write mode, close & reset to start // of byte stream messageBody.reset(); Long length = messageBody.getBodyLength(); logger.debug("***** MESSAGE LENGTH is {} bytes", length); byte[] byteMyMessage = new byte[length.intValue()]; int red = messageBody.readBytes(byteMyMessage); logger.debug( "***** SENDING MESSAGE - \n\n{}\n", new String(byteMyMessage)); } return message; } }); Account account2 = (Account) jmsTemplate.receiveAndConvert(TEST_DEST); assertNotNull("Account MUST return from JMS", account2); assertEquals("Name MUST match", account.getName(), account2.getName()); assertEquals("Description MUST match", account.getDescription(), account2.getDescription()); assertEquals("Balance MUST match", account.getBalance(), account2.getBalance()); } private Account generateTestMessage() { Account account = new Account(); account.setBalance(new BigDecimal(12345.67)); account.setDescription("A no account varmint"); account.setName("Waskally Wabbit"); logger.debug("Generated Test Message: " + account.toString()); return account; } } 4. Visualizing Results Run: mvn clean test See Account XML between the block & Output has been Formatted for clarity ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.gordondickens.jmswithoxm.JmsWithOxmTest INFO o.s.o.j.Jaxb2Marshaller - Creating JAXBContext with classes to be bound [class com.gordondickens.jmswithoxm.Account] DEBUG c.g.j.JmsWithOxmTest - Generated Test Message: Account [name=Waskally Wabbit, description=A no account varmint, balance=12345.670000000000072759576141834259033203125] DEBUG o.s.j.c.JmsTemplate - Executing callback on JMS Session: ActiveMQSession {id=ID:Technophiliac-61135-1296856347600-2:1:1,started=false} DEBUG c.g.j.JmsWithOxmTest - ***** MESSAGE LENGTH is 213 bytes DEBUG c.g.j.JmsWithOxmTest - ***** SENDING MESSAGE - Waskally Wabbit A no account varmint 12345.670000000000072759576141834259033203125 DEBUG o.s.j.c.JmsTemplate - Sending created message: ActiveMQBytesMessage {commandId = 0, responseRequired = false, messageId = null, originalDestination = null, originalTransactionId = null, producerId = null, destination = null, transactionId = null, expiration = 0, timestamp = 0, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = null, replyTo = null, persistent = false, type = null, priority = 0, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@b364dcb, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = false, readOnlyBody = true, droppable = false} ActiveMQBytesMessage{ bytesOut = null, dataOut = null, dataIn = java.io.DataInputStream@1a2d502d } DEBUG o.s.j.c.JmsTemplate - Executing callback on JMS Session: ActiveMQSession {id=ID:Technophiliac-61135-1296856347600-2:2:1,started=true} Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.276 sec 5. Logging Configuration Logback is very similar to Log4J Logback patterns use Log4J characters also See: Logback Pattern Layout Documentation %-5level %logger{5} - %msg%n 6. Maven Configuration Using Logback to support Log4J, SLF4J, Apache (JCL) & Java Util Logging Included IDE builders for STS/Eclipse & IntelliJ IDEA 4.0.0 com.gordondickens.jmswithoxm spring-jms-oxm 1.0.0.CI-SNAPSHOT jar JMS to OXM Spring http://gordondickens.com Sample JMS with OXM Message Conversion gordon.dickens Gordon Dickens [email protected] Author http://www.gordondickens.com 3.0.5.RELEASE 4.8.1 1.1.1 1.6.1 5.4.2 0.9.27 1.2.16 UTF-8 false quick true junit junit ${junit.version} test log4j log4j ${log4j.version} org.slf4j slf4j-api ${slf4j.version} org.slf4j jcl-over-slf4j ${slf4j.version} org.slf4j jul-to-slf4j ${slf4j.version} ch.qos.logback logback-classic ${logback.version} ch.qos.logback logback-core ${logback.version} ch.qos.logback logback-access ${logback.version} org.springframework spring-core ${spring.version} commons-logging commons-logging org.springframework spring-test ${spring.version} test commons-logging commons-logging org.apache.activemq activemq-core ${activemq.version} org.springframework spring-context commons-logging commons-logging commons-logging commons-logging-api org.apache.xbean xbean-spring 3.7 commons-logging commons-logging org.springframework spring-context ${spring.version} org.springframework spring-jms ${spring.version} org.springframework spring-oxm ${spring.version} javax.xml.bind jaxb-api 2.2.2 org.apache.geronimo.specs geronimo-jms_1.1_spec ${jms.version} org.apache.maven.plugins maven-surefire-plugin 2.7.1 org.apache.maven.plugins maven-eclipse-plugin 2.8 true true 2.0 org.springframework.ide.eclipse.core.springbuilder org.springframework.ide.eclipse.core.springnature org.apache.maven.plugins maven-compiler-plugin 2.3.2 1.6 1.6 org.apache.maven.plugins maven-idea-plugin 2.2 true true true 6. Getting the code Code is in my Git Repo: https://github.com/gordonad/core-spring-demos/tree/master/demos/JmsOxmDemo Further Reading Spring Reference for JMS – Section 21.3.1 Using Message Converters Core Spring Training – Where I teach JMS with Spring Enterprise Integration with Spring Training – Where I teach JMS with Spring From http://gordondickens.com/wordpress/2011/02/07/sending-beans-as-xml-with-jmstemplate/
February 8, 2011
by Gordon Dickens
· 19,240 Views
article thumbnail
Spring Data with Redis
The Spring Data project provides a solution for accessing data stored in new emerging technologies like NoSQL databases and cloud based services. When we look into the SpringSource git repository we see a lot of spring-data sub-projects: spring-data-commons: common interfaces and utility class for other spring-data projects. spring-data-column: support for column based databases. It has not started yet, but there will be support for Cassandra and HBase spring-data-document: support for document databases. Currently MongoDB and CouchDB are supported. spring-data-graph: support for graph based databases. Currently Neo4j is supported. spring-data-keyvalue: support for key-value databases. Currently Redis and Riak are supported and probably Membase will be supported in future. spring-data-jdbc-ext: JDBC extensions, as example Oracle RAC connection failover is implemented. spring-data-jpa: simplifies JPA based data access layer. I would like to share with you how you can use Redis. The first step is to download it from the redis.io web page. try.redis-db.com is a useful site where we can run Redis commands. It also provides a step by step tutorial. This tutorial shows us all structures that Redis supports (list, set, sorted set and hashes) and some useful commands. A lot of reputable sites use Redis today. After download and unpacking we should compile Redis (version 2.2, the release candidate is the preferable one to use since some commands do not work in version 2.0.4). make sudo make install Once we run these commands we are all set to run the following five commands: redis-benchmark - for benchmarking Redis server redis-check-aof - check the AOF (Aggregate Objective Function), and it can repair that. redis-check-dump - check rdb files for unprocessable opcodes. redis-cli - Redis client. redis-server - Redis server. We can test Redis server. redis-server [1055] 06 Jan 18:19:15 # Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf' [1055] 06 Jan 18:19:15 * Server started, Redis version 2.0.4 [1055] 06 Jan 18:19:15 * The server is now ready to accept connections on port 6379 [1055] 06 Jan 18:19:15 - 0 clients connected (0 slaves), 1074272 bytes in use and Redis client. redis-cli redis> set my-super-key "my-super-value" OK Now we create a simple Java project in order to show how simple a spring-data-redis module really is. mvn archetype:create -DgroupId=info.pietrowski -DpackageName=info.pietrowski.redis -DartifactId=spring-data-redis -Dpackage=jar Next we have to add in pom.xml milestone spring repository, and add spring-data-redis as a dependency. After that all required dependencies will be fetched. Next we create a resources folder under the main folder, and create application.xml which will have all the configuration. We can configure the JedisConnectionFactory, in two different ways, One - we can provide a JedisShardInfo object in shardInfo property. Two - we can provide host (default localhost), port (default 6379), password (default empty) and timeout (default 2000) properties. One thing to keep in mind is that the JedisShardInfo object has precedence and allows to setup weight, but only allows constructor injection. We can setup the factory to use connection pooling by setting the value of the pooling property to 'true' (default). See application.xml comments to see three different way of configuration. Note: There are two different libraries supported: Jedis and JRedis. They have very similar names and both have the same factory name. See the difference: org.springframework.data.keyvalue.redis.connection.jedis.JedisConnectionFactory org.springframework.data.keyvalue.redis.connection.jredis.JredisConnectionFactory Similar to what we do in Spring, we configure the template object by providing it with a connection factory. We will perform all the operations through this template object. By default we need to provide only Connection Factory, but there are more properties we can provide: exposeConnection (default false) - if we return real connection or proxy object. keySerializer, hashKeySerializer, valueSerializer, hashValueSerializer (default JdkSerializationRedisSerializer) which delegates serialization to Java serialization mechanism. stringSerializer (default StringRedisSerializer) which is simple String to byte[] (and back) serializer with UTF8 encoding. We are ready to execute some code which will be cooperating with the Redis instance. Spring-Data provides us with two ways of interaction, First is by using the execute method and providing a RedisCallback object. Second is by using *Operations helpers (these will be explained later) When we are using RedisCallback we have access to low level Redis commands, see this list of interfaces (I won't put all the methods here because it is huge list): RedisConnection - gathers all Redis commands plus connection management. RedisCommands - gathers all Redis commands (listed beloved). RedisHashCommands - Hash-specific Redis commands. RedisListCommands - List-specific Redis commands. RedisSetCommands - Set-specific Redis commands. RedisStringCommands - key/value specific Redis commands. RedisTxCommands - Transaction/Batch specific Redis commands. RedisZSetCommands - Sorted Set-specific Redis commands. Check RedisCallbackExample class, this was the hard way and the problem is we have to convert our objects into byte arrays in both directions, the second way is easier. Spring Data provides for us with Operations objects, so we have much more simpler API and all byte<->object conversion is made by serializer we setup (or the default one). Higher level API (you will easily recognize *Operation *Commands equivalents): HashOperations - Redis hash operations. ListOperations - Redis list operations. SetOperations - Redis set operations. ValueOperations - Redis 'string' operations. ZSetOperations - Redis sorted set operations. Most of methods get key as first parameters so we have an even better API for multiple operations on the same key: BoundHashOperations - Redis hash operations for specific key. BoundListOperations - Redis list operations for specific key. BoundSetOperations - Redis set operations for specific key. BoundValueOperations - Redis 'string' operations for specific key. BoundZSetOperations - Redis sorted set operations for specific key. Check RedisCallbackExample class to see some easy examples of *Operations usage. One important thing to mention is that you should use stringSerializers for keys, otherwise you will have problems from other clients, because standard serialization adds class information. Otherwise you end up keys such as: "\xac\xed\x00\x05t\x00\x05atInt" "\xac\xed\x00\x05t\x00\nmySuperKey" "\xac\xed\x00\x05t\x00\bsuperKey" Up until now we have just checked the API for Redis, but Spring Data offers more for us. All the cool stuff is in org.springframework.data.keyvalue.redis.support package and all sub-packages. We have: RedisAtomicInteger - Atomic integer (CAS operation) backed by Redis. RedisAtomicLong - Same as previous for Long. RedisList - Redis extension for List, Queue, Deque, BlockingDeque and BlockingQueue with two additional methods List range(start, end) and RedisList trim(start, end). RedisSet - Redis extension for Set with additional methods: diff, diffAndStore, intersect, intersectAndStore, union, unionAndStore. RedisZSet - Redis extension for SortedSet. Note that Comparator is not applicable here so this interface extends normal Set and provide proper methods similar to SortedSet. RedisMap - Redis extension for Map with additional Long increment(key, delta) method Every interface currently has one Default implementation. Check application-support.xml for examples of configuration and RedisSupportClassesExample for examples of use. There is lot of useful information in the comments as well. Summary The library is a first milestone release so there are minor bugs, the documentation isn't as perfect as we used to and the current version needs no stable Redis server. But this is definitely a great library which allows us to use all this cool NoSQL stuff in a "standard" Spring Data Access manner. Awesome job! This post is only useful if you checkout the code: from bitbucket , for the lazy ones here is spring-data-redis zip file as well. This post is originally from http://pietrowski.info/2011/01/spring-data-redis-tutorial/
February 3, 2011
by Sebastian Pietrowski
· 31,210 Views
article thumbnail
Mock Static Methods using Spring Aspects
I am a Spring framework user for last three years and I have really enjoyed working with Spring. One thing that I am seeing these days is the heavy use of AspectJ in most of SpringSource products. Spring Roo is a RAD tool for Java developers which makes use of AspectJ ITD's for separate compilation units. Spring transaction management and exception translation is also done using Aspectj. There are also numerous other usages of Aspectj in Spring products. In this article, I am going to talk about another cool usage of AspectJ by Spring - Mocking Static Methods. These days most of the developers write unit test cases and it is very common to use any of the mocking libraries like EasyMock, Mockito etc. to mock the external dependencies of a class. Using any of these mocking libraries it is very easy to mock calls to other class instance method. But most of these mocking framework does not provide the facility to mock the calls to static methods. Spring provides you the capability to mock static methods by using Spring Aspects library. In order to use this feature you need to add spring-aspects.jar dependency in your pom.xml. org.springframework spring-aspects 3.0.4.RELEASE Next thing you need to do is to convert your project in to a AspectJ project. If you are using Eclipse or STS(SpringSource Tool Suite) you can do that by right-click your project -> configure -> convert to AspectJ project. STS by default has AspectJ plugin, for eclipse users you need to install AspectJ plugin for above to work. I would recommend using STS for developing Spring based applications. The two aspects and one annotation that is of interest in spring-aspects.jar are : AbstractMethodMockingControl : This is an abstract aspect to enable mocking of methods picked out by a pointcut. All the child aspects need to define mockStaticsTestMethod() and methodToMock() pointcuts. The mockStaticTestMethod() pointcut is used to indicate when mocking should be triggered and methodToMock() pointcut is used to define which method invocations to mock. AnnotationDrivenStaticEntityMockingControl : This is the single implementation of AbstractMethodMockingControl aspect which exists in spring-aspects.jar. This is an annotation-based aspect to use in a test build to enable mocking static methods on Entity classes. In this aspect mockStaticTestMethod() pointcut defines that for classes marked with @MockStaticEntityMethods annotation mocking should be triggered and methodToMock() pointcut defines that all the public static methods in the classes marked with @Entity annotation should be mocked. MockStaticEntityMethods : Annotation to indicate a test class for whose @Test methods static methods on Entity classes should be mocked. The AnnotationDrivenStaticEntityMockingControl provide the facility to mock static methods of any class which is marked with @Entity annotation. But usually we would need to mock static method of classes other than marked with @Entity annotation. The only thing we need to do to make it work is to extend AbstractMethodMockingControl aspect and provide definitions for mockStaticsTestMethod() and methodToMock() pointcuts. For example, lets write an aspect which should mock all the public static methods of classes marked with @Component annotation. package com.shekhar.javalobby; import org.springframework.mock.staticmock.AbstractMethodMockingControl; import org.springframework.stereotype.Component; import org.springframework.mock.staticmock.MockStaticEntityMethods;; public aspect AnnotationDrivenStaticComponentMockingControl extends AbstractMethodMockingControl { public static void playback() { AnnotationDrivenStaticComponentMockingControl.aspectOf().playbackInternal(); } public static void expectReturn(Object retVal) { AnnotationDrivenStaticComponentMockingControl.aspectOf().expectReturnInternal(retVal); } public static void expectThrow(Throwable throwable) { AnnotationDrivenStaticComponentMockingControl.aspectOf().expectThrowInternal(throwable); } protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..)); protected pointcut methodToMock() : execution(public static * (@Component *).*(..)); } The only difference between AnnotationDrivenStaticEntityMockingControl(comes with spring-aspects.jar) and AnnotationDrivenStaticComponentMockingControl(custom that we have written above) is in methodToMock() pointcut. In methodToMock() pointcut we have specified that it should mock all the static methods in any class marked with @Component annotation. Now that we have written the custom aspect lets test it. I have created a simple ExampleService with one static method. This is the method which we want to mock. @Component public class ExampleService implements Service { /** * Reads next record from input */ public String getMessage() { return myName(); } public static String myName() { return "shekhar"; } } This class will return "shekhar" when getMessage() method will be called. Lets test this without mocking package com.shekhar.javalobby; import org.junit.Assert; import org.junit.Test; public class ExampleConfigurationTests { private ExampleService service = new ExampleService(); @Test public void testSimpleProperties() throws Exception { String myName = service.getMessage(); Assert.assertEquals("shekhar", myName); } } This test will work fine. Now let's add mocking to this test class. There are two things that we need to do in our test We need to annotate our test with @MockStaticEntityMethods to indicate that static methods of @Component classes will be mocked. Please note that it is not required to use @MockStaticEntityMethods annotation you can create your own annotation and use that in mockStaticsTestMethod() pointcut. So, I could have created an annotation called @MockStaticComponentMethods and used that in mockStaticsTestMethod() pointcut. But I just reused the @MockStaticEntityMethods annotation. In our test methods we need to first invoke the static method which we want to mock so that it gets recorded. Next we need to set our expectation i.e. what should be returned from the mock and finally we need to call the playback method to stop recording mock calls and enter playback state. To make it more concrete lets apply mocking to the above test import org.junit.Assert; import org.junit.Test; import org.springframework.mock.staticmock.MockStaticEntityMethods; @MockStaticEntityMethods public class ExampleConfigurationTests { private ExampleService service = new ExampleService(); @Test public void testSimpleProperties() throws Exception { ExampleService.myName(); AnnotationDrivenStaticComponentMockingControl.expectReturn("shekhargulati"); AnnotationDrivenStaticComponentMockingControl.playback(); String myName = service.getMessage(); Assert.assertEquals("shekhargulati", myName); } } As you can see we annotated the test class with @MockStaticEntityMethods annotation and in the test method we first recorded the call (ExampleService.myName()), then we set the expectations, then we did the playback and finally called the actual code. In this way you can mock the static method of class.
January 25, 2011
by Shekhar Gulati
· 22,788 Views · 1 Like
article thumbnail
Using Default Values for Properties in Spring
I was looking through the Spring Greenhouse application and discovered an existing feature that I was unaware of. We can set a default value when configuring PropertyPlaceholderConfigurer. 1. Set the default value separator in config <-- Ignore file not found --> <-- Ignore when tokens are not found --> ... 2. Set the default values for your properties ... Notes If unspecified, the default separator is a colon “:” This option is not available when using the “context” namespace – (submitted Jira ticket: SPR-7794) From http://gordondickens.com/wordpress/2010/12/06/using-default-values-for-properties-in-spring/
December 30, 2010
by Gordon Dickens
· 52,671 Views
article thumbnail
jQuery Templates – tmpl(), template() and tmplItem()
In the first blog, I made introduction to the jQuery Templates plugin made by Microsoft for the jQuery library. Now in this blog I will pass briefly through the three main functions that are supported by the plugin up to now. - tmpl() and $.tmpl() The purpose of this function is to render the template Syntax: tmpl([data], [options]) $.tmpl(template, [data], [options]) As you can see, the first tmpl() function takes two parameters, while the second takes three parameters. What is the real difference here? Both functions make the same. The difference is that in the second $.tmpl (with jQuery sign) we have template parameter so that this parameter can be string containing markup, HTML Element, or Name of named template. To see this in real-world example, see the complete example at the bottom of this blog. tmpl() Example $("#myTemplate").tmpl(myData).appendTo("ul"); $.tmpl() Example $.tmpl("namedTemplate", myData).appendTo("ul"); - template() and $.template() We can use this function to create named templates. Previously I’ve written an example with $.tmpl() where it’s first parameter is named template. We can create named templates using tempalte or $.template() and use it anywhere else. So, with this function we can simply compile the template by associating it with the given name. Syntax: template([name]) $.template(name, template) Let’s see two simple examples: template() Example $("#myTemplate").template("attendeeTemplate"); $.template() $.template("attendeeTemplate", "${Attendee}"); Usage of the above example would be $.tmpl("attendeeTemplate", Data).appendTo("ol") now you see both $.tmpl and $.template in same scenario - tmplItem() and $.tmplItem() Using this function, we can access the rendered template item. It will retrieve object which has data and nodes properties. Syntax: tmplItem() $.tmplItem(element) And here are the examples: tmplItem() var item = $("font").tmplItem(); $.tmplItem() var item = $.tmplItem("font"); Here is complete example where I’m using all three functions in one scenario Name: Surname: Speaker: Add New HighLight Last Speaker the result is You can simply copy the code and paste it in your VS.NET by creating new page and it will work fine. You don’t need to add scripts manually since I use the scripts directly from Microsoft CDN.
December 15, 2010
by Hajan Selmani
· 34,204 Views
article thumbnail
Getting MySQL work with Entity Framework 4.0
Does MySQL work with Entity Framework 4.0? The answer is: yes, it works! I just put up one experimental project to play with MySQL and Entity Framework 4.0 and in this posting I will show you how to get MySQL data to EF. Also I will give some suggestions how to deploy your applications to hosting and cloud environments. MySQL stuff As you may guess you need MySQL running somewhere. I have MySQL installed to my development machine so I can also develop stuff when I’m offline. The other thing you need is MySQL Connector for .NET Framework. Currently there is available development version of MySQL Connector/NET 6.3.5 that supports Visual Studio 2010. Before you start download MySQL and Connector/NET: MySQL Community Server Connector/NET 6.3.5 If you are not big fan of phpMyAdmin then you can try out free desktop client for MySQL – HeidiSQL. I am using it and I am really happy with this program. NB! If you just put up MySQL then create also database with couple of table there. To use all features of Entity Framework 4.0 I suggest you to use InnoDB or other engine that has support for foreign keys. Connecting MySQL to Entity Framework 4.0 Now create simple console project using Visual Studio 2010 and go through the following steps. 1. Add new ADO.NET Entity Data Model to your project. For model insert the name that is informative and that you are able later recognize. Now you can choose how you want to create your model. Select “Generate from database” and click OK. 2. Set up database connection Change data connection and select MySQL Database as data source. You may also need to set provider – there is only one choice. Select it if data provider combo shows empty value. Click OK and insert connection information you are asked about. Don’t forget to click test connection button to see if your connection data is okay. If everything works then click OK. 3. Insert context name Now you should see the following dialog. Insert your data model name for application configuration file and click OK. Click next button. 4. Select tables for model Now you can select tables and views your classes are based on. I have small database with events data. Uncheck the checkbox “Include foreign key columns in the model” – it is damn annoying to get them away from model later. Also insert informative and easy to remember name for your model. Click finish button. 5. Define your classes Now it’s time to define your classes. Here you can see what Entity Framework generated for you. Relations were detected automatically – that’s why we needed foreign keys. The names of classes and their members are not nice yet. After some modifications my class model looks like on the following diagram. Note that I removed attendees navigation property from person class. Now my classes look nice and they follow conventions I am using when naming classes and their members. NB! Don’t forget to see properties of classes (properties windows) and modify their set names if set names contain numbers (I changed set name for Entity from Entity1 to Entities). 6. Let’s test! Now let’s write simple testing program to see if MySQL data runs through Entity Framework 4.0 as expected. My program looks for events where I attended. using(var context = new MySqlEntities()) { var myEvents = from e in context.Events from a in e.Attendees where a.Person.FirstName == "Gunnar" && a.Person.LastName == "Peipman" select e; Console.WriteLine("My events: "); foreach(var e in myEvents) { Console.WriteLine(e.Title); } } Console.ReadKey(); And when I run it I get the result shown on screenshot on right. I checked out from database and these results are correct. At first run connector seems to work slow but this is only the effect of first run. As connector is loaded to memory by Entity Framework it works fast from this point on. Now let’s see what we have to do to get our program work in hosting and cloud environments where MySQL connector is not installed. Deploying application to hosting and cloud environments If your hosting or cloud environment has no MySQL connector installed you have to provide MySQL connector assemblies with your project. Add the following assemblies to your project’s bin folder and include them to your project (otherwise they are not packaged by WebDeploy and Azure tools): MySQL.Data MySQL.Data.Entity MySQL.Web You can also add references to these assemblies and mark references as local so these assemblies are copied to binary folder of your application. If you have references to these assemblies then you don’t have to include them to your project from bin folder. Also add the following block to your application configuration file. ... ... Conclusion It was not hard to get MySQL connector installed and MySQL connected to Entity Framework 4.0. To use full power of Entity Framework we used InnoDB engine because it supports foreign keys. It was also easy to query our model. To get our project online we needed some easy modifications to our project and configuration files.
December 10, 2010
by Gunnar Peipman
· 24,660 Views
article thumbnail
Changing Eclipse Default Encoding to UTF-8 for JSP files
Try creating a new JSP file in your Eclipse and you’ll notice that the JSP page directive will have encoding something like: But for a better I18N and L10N support, it is recommended to follow UTF-8 encoding where ever possible. So, how do we change the default JSP file encoding to UTF-8 in eclipse? Simple. Just do these things: In Eclipse, go to Windows -> Preferences -> Web -> JSP Files Select UTF-8 encoding from the Encoding dropdown box there. That’s it! And if you wonder how this change works, you can very well see that. In the same Preferences window, go to this location: Preferences -> Web -> JSP Files -> Editor -> Templates. Then in the right hand side, you’ll see a list of templates defined for JSP files. And in a new JSP file template, you can see this code: Here as you might have guessed, the ${encoding} will be replaced by whatever we set in the above step. The same method can be used to change the default encoding type for other file types too (css, html). From http://veerasundar.com/blog/2010/12/changing-eclipse-default-encoding-to-utf-8-for-jsp-files/
December 8, 2010
by Veera Sundar
· 26,814 Views · 1 Like
article thumbnail
ASP.NET MVC 3: Building simple image editor using WebImage helper
In my previous posting about WebImage helper I introduced how to use WebImage for different image manipulations. In this posting I will show you how to build simple online image editor using WebImage helper. Source code You can find source code of this example from Visual Studio 2010 experiments repository at GitHub. Source code repository GitHub Simple image editor belongs to Experiments.AspNetMvc3NewFeatures solution, project name is Experiments.AspNetMvc3NewFeatures.Aspx. Here you can see the screenshot of simple image editor. Four simple operations is enough for current example. Building editor view Before going to controller that is extremely simple – believe me, it is no-brainer – let’s take a look at view. The editor is made up from following parts: image tag that shows image with current effects, effects checkboxes, JavaScript that requests image with selected effects from server. Here is the view. Image Workshop Image Workshop Flip horizontally Flip vertically Rotate left Rotate right The JavaScript function updateImage() checks what checkboxes are checked and creates query string for GetImage controller action. This query string contains values only for applied effects. Controller actions When you take a look at image definition in view you can see that we need two separate actions – one that returns editor view and the other that returns image. I said before that controller is extremely simple. Don’t mind my not so nice solution for image action – it is my working draft. public class ImageWorkshopController : Controller { [HttpGet] public ActionResult Index() { return View(); } public void GetImage(string horizontalFlip="", string verticalFlip="", string rotateLeft="", string rotateRight="") { var imagePath = Server.MapPath("~/images/bunny-peanuts.jpg"); var image = new WebImage(imagePath); if (!string.IsNullOrWhiteSpace(verticalFlip)) image = image.FlipVertical(); if (!string.IsNullOrWhiteSpace(horizontalFlip)) image = image.FlipHorizontal(); if (!string.IsNullOrWhiteSpace(rotateLeft)) image = image.RotateLeft(); if (!string.IsNullOrWhiteSpace(rotateRight)) image = image.RotateRight(); image.Write(); } } Applying effects to image is very easy. We just check the values sent from view and apply the effect only if appropriate value is not null or empty string. That’s why I created query string with effect values as ones ("1") in JavaScript.
November 9, 2010
by Gunnar Peipman
· 16,622 Views
article thumbnail
WCF: The maximum message size quota for incoming messages (65536) has been exceeded
When using WCF services you may get the following error: "The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element." This error is given because of size limits set to responses in your application configuration. You need to increase the value of two limiting parameters: maxBufferSize and maxReceivedMessageSize. In my example these values are set to 5000000. After increasing these values your service requests should work normally.
November 8, 2010
by Gunnar Peipman
· 33,624 Views
article thumbnail
ASP.NET: Converting X-Forwarded-For To REMOTE_HOST
Just keeping notes here. If you’re using IIS Mod Rewrite or if you’re running a reverse proxy or a non-transparent load balancer, you may find the request URL server variable mismatching and the REMOTE_ADDR server variable coming back as the IP address of the proxy server or as the load balancer IP. This is no good, because all of the user’s IP address information is lost. Well, almost lost. What should happen is the the reverse proxy is supposed to add an X-Forwarded-For HTTP header in the request headers containing the user’s IP address, as well as X-Original-URL. This can then be read back by the web server. The problem is, even with X-Forwarded-For being passed in to the web server, REMOTE_ADDR is still wrong. I’m looking for the easiest path to just fix this once and for all without delving into web application code. So I’m playing with this simple global.asax tweak to fix this. I haven’t fully tested this yet so, again, just taking notes here .. void Application_BeginRequest(object sender, EventArgs e) { var ss = Request.ServerVariables["SERVER_SOFTWARE"]; if (!string.IsNullOrEmpty(ss) && ss.Contains("Microsoft-IIS")) // doesn't work w/ Cassini { string SourceIP = String.IsNullOrEmpty(Request.ServerVariables["HTTP_X_FORWARDED_FOR"]) ? Request.ServerVariables["REMOTE_ADDR"] : Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; Request.ServerVariables.Set("REMOTE_ADDR", SourceIP); Request.ServerVariables.Set("REMOTE_HOST", SourceIP); string OrigUrl = Request.ServerVariables["HTTP_X_ORIGINAL_URL"]; if (!string.IsNullOrEmpty(OrigUrl)) { var url = new Uri(Request.Url, OrigUrl); Request.ServerVariables.Set("SERVER_NAME", url.Host); Request.ServerVariables.Set("SERVER_PORT", url.Port.ToString()); } } }
November 4, 2010
by Jon Davis
· 16,460 Views
article thumbnail
MyBatis (formerly iBatis) – Examples and Hints using SELECT, INSERT and UPDATE Annotations
MyBatis is a lightweight persistence framework for Java and .NET. This blog entry addresses the Java side. MyBatis is an alternative positioned somewhere between plain JDBC and ORM frameworks (e.g. EclipseLink or Hibernate). MyBatis usually uses XML, but it also supports annotations since version 3. The documentation is very detailed for XML, but lacks annotation examples. Just the Annotations itself are described, but no examples how to use them. I could not find any good and easy examples anywhere, so I will describe some very basic examples for SELECT, INSERT and UPDATE statements by implementing a Data Access Object (DAO) using MyBatis. These examples are a good starting point to create more complex MyBatis queries using a DAO. You can find the full source code at the end of this blog. A simple SQL-Table I use a very simple table with two attributes. The name of the table is “simple_information”. The primary key is a Integer and may not be null (info_id). The only real data is a character and may also not be null (info_content). That is enough “complexity” to learn the usage of MyBatis annotations. The Java class “SimpleInformationEntity” is a POJO which contains these two attributes. @SELECT-Statement The @Select annotation is very easy to use, if you want to use exactly one paramter. If you need more than one paramter, use the @Param annotation (which is described below at the update example). You do not have to map the found information to a SimpleInformationEntity object, as you would have to do with a JDBC ResultSet. The magic of the framework does this for you. final String GET_INFO = “SELECT * FROM simple_information WHERE info_id = #{info_id}”; @Select(GET_INFO) public SimpleInformationEntity getSimpleInformationById(int info_id) throws Exception; @INSERT-Statement You can use the object (which you want to be persist) as parameter. You do not have to use several parameters for each attribute of the object. The magic of the framework does this for you. final String PERSIST_INFO = “INSERT INTO simple_information(info_id, info_content) VALUES (#{infoId}, #{infoContent})”; @Insert(PERSIST_INFO) public int persistInformation(SimpleInformationEntity simpleInfo) throws Exception; @UPDATE-Statement You cannot use more than one parameter within a method. If you want to understand why, look at some MyBatis XML examples in the documenation: There you use the attribute “parameterType”, which must be exactly one “parameter”! So you will get a (strange) exception, if you use two or more parameters. Instead you have to use the @Param annotation, if you need more than one parameter. final String UPDATE_INFO = “UPDATE simple_information SET info_content = #{newInfo} WHERE info_id = #{infoId}”; @Update(UPDATE_INFO) public int updateInformation(@Param(“infoId”) int info_id, @Param(“newInfo”) String new_content) throws Exception; Configuration You have to add your MyBatis-Interface for the Mapper to the SQLSessionFactory: sqlSessionFactory.getConfiguration().addMapper(InfoMapper.class); Some Hints for developing with MyBatis The following means helped me a lot to use MyBatis annotations despite the lack of documentation about using annotations: - MyBatis is open source! So add the sources to your build path and use the debugging function of your IDE to enter the MyBatis source code while executing some queries. You will see what MyBatis expects as input and how it is processed. - Read the documentation about using MyBatis XML. This does not really make any sense you think? It does! The processing deep inside MyBatis does not change if you use annotations instead of XML. It is just another way to develop persistence queries. E.g. if you know that a XML select query may just use exactly one parameterType-attribute, then you know that you may just use one parameter in an annotation-based method too! If you need more parameters, you have to use the @Param annotation. - If you get any strange exception that does not make any sense, then clean and re-compile your project. This often helps, because as with other persistence frameworks such as Hibernate, the bytecode enhancement sometimes confuses your IDE. Conclusion: @MyBatis-Team: Improve and extend the documentation instead of improving the framework itself! MyBatis is a nice lightweigt persistence framework. But the documentation is not enough detailed. Some important information is completely missing. Especially, if you are a newbie to MyBatis / iBatis, it is very tough to develop with MyBatis using annotations instead of XML. Besides the usage of annotations, another good example for missing documentation is how to configure transactions in MyBatis by using JNDI and a J2EE / JEE Application server. You have to use google to find out, and if you are lucky you will find a mailing list or blog entry describing your problem. If not, you have to try it out. The missing documentation makes MyBatis much more tough than it actually is. So in the next months, the MyBatis team should improve and extend the documentation instead of improving the framework itself… Best regards, Kai Wähner (Twitter: @Kai Waehner) [Content from my Blog: MyBatis (formerly iBatis) - Examples and Hints using Select, Insert and Update Annotations - Kai Wähner's IT-Blog] Appendix: Source Code Here you see all the necessary source code, also including a MyBatis Connection Factory, which reads the configuration data from a XML file. ############################################################################ Connection Factory (using a static initializer) ############################################################################ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import de.waehner.kai.persistence.InfoDAO.InfoMapper; public class MyBatisConnectionFactory { private static SqlSessionFactory sqlSessionFactory; static { Reader reader = null; try { InputStream in = MyBatisConnectionFactory.class.getResourceAsStream(“myBatisConfiguration.xml”); reader = new InputStreamReader(in); if (sqlSessionFactory == null) { sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); sqlSessionFactory.getConfiguration().addMapper(InfoMapper.class); } in.close(); } catch (FileNotFoundException fileNotFoundException) { fileNotFoundException.printStackTrace(); } catch (IOException iOException) { iOException.printStackTrace(); } } public static SqlSessionFactory getSqlSessionFactory() { return sqlSessionFactory; } } ############################################################################ Data Acces Object (including the MyBatis-Mapper as inner Class) ############################################################################ import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; public class InfoDAO { public interface InfoMapper { final String GET_INFO = “SELECT * FROM simple_information WHERE info_id = #{info_id}”; @Select(GET_INFO) public SimpleInformationEntity getSimpleInformationById(int info_id) throws Exception; final String PERSIST_INFO = “INSERT INTO simple_information(info_id, info_content) VALUES (#{infoId}, #{infoContent})”; @Insert(PERSIST_INFO) public int persistInformation(SimpleInformationEntity simpleInfo) throws Exception; final String UPDATE_INFO = “UPDATE simple_information SET info_content = #{newInfo} WHERE info_id = #{infoId}”; @Update(UPDATE_INFO) public int updateInformation(@Param(“infoId”) int info_id, @Param(“newInfo”) String new_content) throws Exception; } public SimpleInformationEntity getSingleAlarm(int info_id) throws Exception { SqlSessionFactory sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory(); SqlSession session = sqlSessionFactory.openSession(); try { InfoMapper mapper = session.getMapper(InfoMapper.class); SimpleInformationEntity simpleInfo = mapper.getSimpleInformationById(info_id); return simpleInfo; } finally { session.close(); } } public int persistInformation(SimpleInformationEntity simpleInfo) throws Exception { SqlSessionFactory sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory(); SqlSession session = sqlSessionFactory.openSession(); try { InfoMapper mapper = session.getMapper(InfoMapper.class); int answer = mapper.persistInformation(simpleInfo); return answer; } finally { session.close(); } } public int updateInformation(int info_id, String new_content) throws Exception { SqlSessionFactory sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory(); SqlSession session = sqlSessionFactory.openSession(); try { InfoMapper mapper = session.getMapper(InfoMapper.class); int answer = mapper.updateInformation(info_id, new_content); return answer; } finally { session.close(); } } } ############################################################################ SimpleInformation Entity (a simple POJO) ############################################################################ import java.io.Serializable; public class SimpleInformationEntity implements Serializable{ private static final long serialVersionUID = -821826330941829539L; private int infoId; private String infoContent; public int getInfoId() { return infoId; } public void setInfoId(int infoId) { this.infoId = infoId; } public String getInfoContent() { return infoContent; } public void setInfoContent(String infoContent) { this.infoContent = infoContent; } }
November 2, 2010
by Kai Wähner DZone Core CORE
· 79,657 Views · 2 Likes
article thumbnail
Generate, Rename and Delete Getters/Setters Instantly in Eclipse
despite the arguments and debates about getters and setters in java, the fact is that they’re a reality and you have to work with them. but managing getters and setters is a time-consuming effort. creating a getter/setter for 5 fields in a class can take minutes, renaming one is error-prone and deleting one is just plain inconvenient. there are options like project lombok (that implicitly creates getters/setters without the need to code them) and you could avoid getters/setters altogether by redesigning your classes. but these options aren’t always available, so it’s a good thing eclipse has some handy features for managing getters and setters. combined with the ability to generate constructors based on fields , you can get the boilerplate code out of the way in seconds and get on with the real coding. generate getters and setters to generate getters and setters, do the following: create the fields you want in the class then press alt+shift+s, r . a dialog will pop up allowing you to choose the fields you want to generate getters and setters for. click select all to create getters/setters for all fields. of course you can choose individual fields as required. change insertion point to last member . this tells eclipse that you want to put the methods at the bottom of the class. this is normally the best option for me as i want them out of the way. click ok . eclipse will create the getters and setters for you. here’s an example of what the dialog should look like. note: by default, eclipse doesn’t allow you to create a setter for a final field – the setter just doesn’t appear in the dialog. this can be a nuisance, especially if you’ve enabled autoformatting to make fields final where possible. to bypass this restriction, enable the checkbox allow setters for final fields on the dialog. the setter for the field will now appear in the dialog. once you click ok, eclipse will remove the final keyword from the field and generate the setter. eclipse also remembers this setting. another way to add just a single getter/setter is to position your cursor anywhere in the class (outside any method), start typing either “get” or “set” and press ctrl+space . the options on the autocomplete menu will include any getters/setters of fields that don’t have any defined yet. this is a quick way to create a single getter/setter but isn’t geared for bulk creation. here’s an example of how the autocomplete looks: rename getters and setters the easiest way to rename getters/setters is to use the rename refactoring. place your cursor on the field name (anywhere in the class, not just the declaration) and press alt+shift+r . if you’re using in-place rename (the default), then just rename the field, press enter and eclipse will rename the corresponding getters and setters as well. if you’ve chosen to use the classic refactor dialog (see note below) then make sure you enable rename getter and rename setter on the rename dialog. note: you can choose to do renaming using the traditional rename dialog by going to window > preferences > java and unchecking rename in editor without dialog . i prefer using the rename dialog as it highlights the whole name by default making it easier to overwrite and i have the option of not renaming the getters and setters if i don’t want to. the eclipse default these days is to use the new in-place renaming. although eclipse will rename the getter/setter, it won’t rename the argument passed to the setter method. if you want consistency, you can navigate to that method (eg. using ctrl+o ) and rename the argument yourself. delete getters and setters deleting getters and setters isn’t as straightforward as just deleting the field in the editor. however, you can delete a field and its getters/setters from the outline view. open the outline view ( alt+shift+q, o ), select the field you want to delete and press delete (or right-click, delete). eclipse will ask you whether you want to delete the getters/setters as well. just choose yes to all and they will be removed. you need to have fields visible in the outline view to use this feature (ie. untoggle the hide fields button ). you can select multiple fields simultaneously. and you can delete individual getters/setters (excluding the field) by just selecting the getter/setter and pressing delete . from http://eclipseone.wordpress.com/2010/10/26/generate-rename-and-delete-getterssetters-in-eclipse/
October 27, 2010
by Byron M
· 157,828 Views · 2 Likes
article thumbnail
Manage Hierarchical Data using Spring, JPA and Aspects
Managing hierarchical data using two dimentional tables is a pain. There are some patterns to reduce this pain. One such solution is described here. This article is about implementing the same using Spring, JPA, Annotations and Aspects. Please go through follow the link to better understand this solution described. The purpose is to come up with a component that will remove the boiler-plate code in the business layer to handle hierarchical data. Summary Create a base class for Entities used to represent Hierarchical data Create annotation classes Code the Aspect that will execute addional steps for managing Hierarchical data. (Heart of the solution) Now the Aspect can be used everywhere Hierarchical data is used. Detail Create base class for Entities used to represent Hierarchical data. The purpose of the super class is to encapsulate all the common attrubutes and operations required for managing hierarchical data in a table. Please note that the class is annotated as @MappedSuperclass. The methods are meant to generate queries required to perform CRUD operations on the Table. Their use will be more clear later in the article when we will revisit HierarchicalEntity. Now any Entity that extends this class will have all the attributes required to manage hierarchical data. import com.es.clms.aspect.HierarchicalEntity; import javax.persistence.EntityListeners; import javax.persistence.MappedSuperclass; @MappedSuperclass @EntityListeners({HierarchicalEntity.class}) public abstract class AbstractHierarchyEntity implements Serializable { protected Long parentId; protected Long lft; protected Long rgt; public String getMaxRightQuery() { return "Select max(e.rgt) from " + this.getClass().getName() + " e"; } public String getQueryForParentRight() { return "Select e.rgt from " + this.getClass().getName() + " e where e.id = ?1"; } public String getDeleteStmt() { return "Delete from " + this.getClass().getName() + " e Where e.lft between ?1 and ?2"; } public String getUpdateStmtForFirst() { return "Update " + this.getClass().getName() + " e set e.lft = e.lft + ?2 Where e.lft >= ?1"; } public String getUpdateStmtForRight() { return "Update " + this.getClass().getName() + " e set e.rgt = e.rgt + ?2 Where e.rgt >= ?1"; } . . .//Getter and setters for all the attributes. } Create annotation classes The following is an annotation class that will be used to annotate the methods that perform CRUD operations on hierarchical data. It is followed by an enum that will decide the type of CRUD operation to be performed. These classes will make more sense after the next section. import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface HierarchicalOperation { HierarchicalOperationType operationType(); } /** * Enum - Type of CRUD operation. */ public enum HierarchicalOperationType { SAVE, DELETE; } Code the Aspect that will execute addional steps for managing Hierarchical data. HierarchicalEntity is an aspect that performs the additional logic required to manage the hierarchical data as descriped in the article here. This is the first time I have used an Aspect, therefore I am sure that there are better ways to do this. Those of you, who are good at it, please improve this part of code. This class is annotated as @Aspect. The pointcut will intercept any method anotated with HierarchicalOperation and has a input of type AbstractHierarchyEntity. A sample its usage is in next section. operation method is annotated to be executed before the pointcut. Based on the HierarchicalOperationType passed, this method will either execute the additional tasks required to save or delete the hierarchical record. This is where the methods defined in AbstractHierarchyEntity for generating JPA Queries are used. GenericDAOHelper is a utility class for using JPA. import com.es.clms.annotation.HierarchicalOperation; import com.es.clms.annotation.HierarchicalOperationType; import com.es.clms.common.GenericDAOHelper; import com.es.clms.model.AbstractHierarchyEntity; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Service; import org.springframework.beans.factory.annotation.Autowired; @Aspect @Service("hierarchicalEntity") public class HierarchicalEntity { @Autowired private GenericDAOHelper genericDAOHelper; @Pointcut(value = "execution(@com.es.clms.annotation.HierarchicalOperation * *(..)) " + "&& args(AbstractHierarchyEntity)") private void hierarchicalOps() { } /** * * @param jp * @param hierarchicalOperation */ @Before("hierarchicalOps() && @annotation(hierarchicalOperation) ") public void operation(final JoinPoint jp, final HierarchicalOperation hierarchicalOperation) { if (jp.getArgs().length != 1) { throw new IllegalArgumentException( "Expecting only one parameter of type AbstractHierarchyEntity in " + jp.getSignature()); } if (HierarchicalOperationType.SAVE.equals( hierarchicalOperation.operationType())) { save(jp); } else if (HierarchicalOperationType.DELETE.equals( hierarchicalOperation.operationType())) { delete(jp); } } /** * * @param jp */ private void save(JoinPoint jp) { AbstractHierarchyEntity entity = (AbstractHierarchyEntity) jp.getArgs()[0]; if (entity == null) return; if (entity.getParentId() == null) { Long maxRight = (Long) genericDAOHelper.executeSingleResultQuery( entity.getMaxRightQuery()); if (maxRight == null) { maxRight = 0L; } entity.setLft(maxRight + 1); entity.setRgt(maxRight + 2); } else { Long parentRight = (Long) genericDAOHelper.executeSingleResultQuery( entity.getQueryForParentRight(), entity.getParentId()); entity.setLft(parentRight); entity.setRgt(parentRight + 1); genericDAOHelper.executeUpdate( entity.getUpdateStmtForFirst(), parentRight, 2L); genericDAOHelper.executeUpdate( entity.getUpdateStmtForRight(), parentRight, 2L); } } /** * * @param jp */ private void delete(JoinPoint jp) { AbstractHierarchyEntity entity = (AbstractHierarchyEntity) jp.getArgs()[0]; genericDAOHelper.executeUpdate( entity.getDeleteStmt(), entity.getLft(), entity.getRgt()); Long width = (entity.getRgt() - entity.getLft()) + 1; genericDAOHelper.executeUpdate( entity.getUpdateStmtForFirst(), entity.getRgt(), width * (-1)); genericDAOHelper.executeUpdate( entity.getUpdateStmtForRight(), entity.getRgt(), width * (-1)); } } Sample Usage From this point on you don't have to worry about the additional tasks required for managing the data. Just use the HierarchicalOperation anotation with appropriate HierarchicalOperationType. Below is a sample use of the code developed so far. @HierarchicalOperation(operationType = HierarchicalOperationType.SAVE) public long save(VariableGroup group) { entityManager.persist(group); return group.getId(); } @HierarchicalOperation(operationType = HierarchicalOperationType.DELETE) public void delete(VariableGroup group) { entityManager.remove(entityManager.merge(group)); } http://rajeshkilango.blogspot.com/2010/10/manage-hierarchical-data-using-spring.html
October 21, 2010
by Rajesh Ilango
· 17,183 Views
article thumbnail
Tutorial: Linked/Cascading ExtJS Combo Boxes using Spring MVC 3 and Hibernate 3.5
this post will walk you through how to implement extjs linked/cascading/nested combo boxes using spring mvc 3 and hibernate 3.5. i am going to use the classic linked combo boxes: state and cities. in this example, i am going to use states and cities from brazil! what is our main goal? when we select a state from the first combo box, the application will load the second combo box with the cities that belong to the selected state. there are two ways to implement it. the first one is to load all the information you need for both combo boxes, and when user selects a state, the application will filter the cities combo box according to the selected state. the second one is to load information only to populate the state combo box. when user selects a state, the application will retrieve all the cities that belong to the selected state from database. which one is best? it depends on the amount of data you have to retrieve from your database. for example: you have a combo box that lists all the countries in the world. and the second combo box represents all the cities in the world. in this case, scenario number 2 is the best option, because you will have to retrieve a large amount of data from the database. ok. let’s get into the code. i’ll show how to implement both scenarios. first, let me explain a little bit of how the project is organized: let’s take a look at the java code. basedao: contains the hibernate template used for citydao and statedao. package com.loiane.dao; import org.hibernate.sessionfactory; import org.springframework.beans.factory.annotation.autowired; import org.springframework.orm.hibernate3.hibernatetemplate; import org.springframework.stereotype.repository; @repository public abstract class basedao { private hibernatetemplate hibernatetemplate; public hibernatetemplate gethibernatetemplate() { return hibernatetemplate; } @autowired public void setsessionfactory(sessionfactory sessionfactory) { hibernatetemplate = new hibernatetemplate(sessionfactory); } } citydao: contains two methods: one to retrieve all cities from database (used in scenario #1), and one method to retrieve all the cities that belong to a state (used in scenario #2). package com.loiane.dao; import java.util.list; import org.hibernate.criterion.detachedcriteria; import org.hibernate.criterion.restrictions; import org.springframework.stereotype.repository; import com.loiane.model.city; @repository public class citydao extends basedao{ public list getcitylistbystate(int stateid) { detachedcriteria criteria = detachedcriteria.forclass(city.class); criteria.add(restrictions.eq("stateid", stateid)); return this.gethibernatetemplate().findbycriteria(criteria); } public list getcitylist() { detachedcriteria criteria = detachedcriteria.forclass(city.class); return this.gethibernatetemplate().findbycriteria(criteria); } } statedao: contains only one method to retrieve all the states from database. package com.loiane.dao; import java.util.list; import org.hibernate.criterion.detachedcriteria; import org.springframework.stereotype.repository; import com.loiane.model.state; @repository public class statedao extends basedao{ public list getstatelist() { detachedcriteria criteria = detachedcriteria.forclass(state.class); return this.gethibernatetemplate().findbycriteria(criteria); } } city: represents the city pojo, represents the city table. package com.loiane.model; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.id; import javax.persistence.table; import org.codehaus.jackson.annotate.jsonautodetect; @jsonautodetect @entity @table(name="city") public class city { private int id; private int stateid; private string name; //getters and setters } state: represents the state pojo, represents the state table. package com.loiane.model; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.id; import javax.persistence.table; import org.codehaus.jackson.annotate.jsonautodetect; @jsonautodetect @entity @table(name="state") public class state { private int id; private int countryid; private string code; private string name; //getters and setters } cityservice: contains two methods: one to retrieve all cities from database (used in scenario #1), and one method to retrieve all the cities that belong to a state (used in scenario #2). only makes a call to citydao class. package com.loiane.service; import java.util.list; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.service; import com.loiane.dao.citydao; import com.loiane.model.city; @service public class cityservice { private citydao citydao; public list getcitylistbystate(int stateid) { return citydao.getcitylistbystate(stateid); } public list getcitylist() { return citydao.getcitylist(); } @autowired public void setcitydao(citydao citydao) { this.citydao = citydao; } } stateservice: contains only one method to retrieve all the states from database. makes a call to statedao. package com.loiane.service; import java.util.list; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.service; import com.loiane.dao.statedao; import com.loiane.model.state; @service public class stateservice { private statedao statedao; public list getstatelist() { return statedao.getstatelist(); } @autowired public void setstatedao(statedao statedao) { this.statedao = statedao; } } citycontroller: contains two methods: one to retrieve all cities from database (used in scenario #1), and one method to retrieve all the cities that belong to a state (used in scenario #2). only makes a call to cityservice class. both methods return a json object that looks like this: {"data":[ {"stateid":1,"name":"acrelândia","id":1}, {"stateid":1,"name":"assis brasil","id":2}, {"stateid":1,"name":"brasiléia","id":3}, {"stateid":1,"name":"bujari","id":4}, {"stateid":1,"name":"capixaba","id":5}, {"stateid":1,"name":"cruzeiro do sul","id":6}, {"stateid":1,"name":"epitaciolândia","id":7}, {"stateid":1,"name":"feijó","id":8}, {"stateid":1,"name":"jordão","id":9}, {"stateid":1,"name":"mâncio lima","id":10}, ]} class: package com.loiane.web; import java.util.hashmap; import java.util.map; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.controller; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestparam; import org.springframework.web.bind.annotation.responsebody; import com.loiane.service.cityservice; @controller @requestmapping(value="/city") public class citycontroller { private cityservice cityservice; @requestmapping(value="/getcitiesbystate.action") public @responsebody map getcitiesbystate(@requestparam int stateid) throws exception { map modelmap = new hashmap(3); try{ modelmap.put("data", cityservice.getcitylistbystate(stateid)); return modelmap; } catch (exception e) { e.printstacktrace(); modelmap.put("success", false); return modelmap; } } @requestmapping(value="/getallcities.action") public @responsebody map getallcities() throws exception { map modelmap = new hashmap(3); try{ modelmap.put("data", cityservice.getcitylist()); return modelmap; } catch (exception e) { e.printstacktrace(); modelmap.put("success", false); return modelmap; } } @autowired public void setcityservice(cityservice cityservice) { this.cityservice = cityservice; } } statecontroller: contains only one method to retrieve all the states from database. makes a call to stateservice. the method returns a json object that looks like this: {"data":[ {"countryid":1,"name":"acre","id":1,"code":"ac"}, {"countryid":1,"name":"alagoas","id":2,"code":"al"}, {"countryid":1,"name":"amapá","id":3,"code":"ap"}, {"countryid":1,"name":"amazonas","id":4,"code":"am"}, {"countryid":1,"name":"bahia","id":5,"code":"ba"}, {"countryid":1,"name":"ceará","id":6,"code":"ce"}, {"countryid":1,"name":"distrito federal","id":7,"code":"df"}, {"countryid":1,"name":"espírito santo","id":8,"code":"es"}, {"countryid":1,"name":"goiás","id":9,"code":"go"}, {"countryid":1,"name":"maranhão","id":10,"code":"ma"}, {"countryid":1,"name":"mato grosso","id":11,"code":"mt"}, {"countryid":1,"name":"mato grosso do sul","id":12,"code":"ms"}, {"countryid":1,"name":"minas gerais","id":13,"code":"mg"}, {"countryid":1,"name":"pará","id":14,"code":"pa"}, ]} class: package com.loiane.web; import java.util.hashmap; import java.util.map; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.controller; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.responsebody; import com.loiane.service.stateservice; @controller @requestmapping(value="/state") public class statecontroller { private stateservice stateservice; @requestmapping(value="/view.action") public @responsebody map view() throws exception { map modelmap = new hashmap(3); try{ modelmap.put("data", stateservice.getstatelist()); return modelmap; } catch (exception e) { e.printstacktrace(); modelmap.put("success", false); return modelmap; } } @autowired public void setstateservice(stateservice stateservice) { this.stateservice = stateservice; } } inside the webcontent folder we have: ext-3.2.1 – contains all extjs files js – contains all javascript files i implemented for this example. liked-comboboxes-local.js contains the combo boxes for scenario #1; liked-comboboxes-remote.js contains the combo boxes for scenario #2; linked-comboboxes.js contains a tab panel that contains both scenarios. now let’s take a look at the extjs code. scenario number 1: retrieve all the data from database to populate both combo boxes. will user filter on cities combo box. liked-comboboxes-local.js var localform = new ext.formpanel({ width: 400 ,height: 300 ,style:'margin:16px' ,bodystyle:'padding:10px' ,title:'linked combos - local filtering' ,defaults: {xtype:'combo'} ,items:[{ fieldlabel:'select state' ,displayfield:'name' ,valuefield:'id' ,store: new ext.data.jsonstore({ url: 'state/view.action', remotesort: false, autoload:true, idproperty: 'id', root: 'data', totalproperty: 'total', fields: ['id','name'] }) ,triggeraction:'all' ,mode:'local' ,listeners:{select:{fn:function(combo, value) { var combocity = ext.getcmp('combo-city-local'); combocity.clearvalue(); combocity.store.filter('stateid', combo.getvalue()); } } },{ fieldlabel:'select city' ,displayfield:'name' ,valuefield:'id' ,id:'combo-city-local' ,store: new ext.data.jsonstore({ url: 'city/getallcities.action', remotesort: false, autoload:true, idproperty: 'id', root: 'data', totalproperty: 'total', fields: ['id','stateid','name'] }) ,triggeraction:'all' ,mode:'local' ,lastquery:'' }] }); the state combo box is declared on lines 9 to 28. the city combo box is declared on lines 31 to 46. note that both stores are loaded when we load the page, as we can see in lines 15 and 38 (autoload:true). the state combo box has select event listener that, when executed, filters the cities combo (the child combo) based on the currently selected state. you can see it on lines 23 to 28. cities combo has lastquery:”" . this is to fool internal combo filtering routines on the first page load. the cities combo just thinks that it has already been expanded once. scenario number 2: retrieve all the state data from database to populate state combo. when user selects a state, application will retrieve from database only selected information. liked-comboboxes-remote.js: var databaseform = new ext.formpanel({ width: 400 ,height: 200 ,style:'margin:16px' ,bodystyle:'padding:10px' ,title:'linked combos - database' ,defaults: {xtype:'combo'} ,items:[{ fieldlabel:'select state' ,displayfield:'name' ,valuefield:'id' ,store: new ext.data.jsonstore({ url: 'state/view.action', remotesort: false, autoload:true, idproperty: 'id', root: 'data', totalproperty: 'total', fields: ['id','name'] }) ,triggeraction:'all' ,mode:'local' ,listeners: { select: { fn:function(combo, value) { var combocity = ext.getcmp('combo-city'); //set and disable cities combocity.setdisabled(true); combocity.setvalue(''); combocity.store.removeall(); //reload city store and enable city combobox combocity.store.reload({ params: { stateid: combo.getvalue() } }); combocity.setdisabled(false); } } } },{ fieldlabel:'select city' ,displayfield:'name' ,valuefield:'id' ,disabled:true ,id:'combo-city' ,store: new ext.data.jsonstore({ url: 'city/getcitiesbystate.action', remotesort: false, idproperty: 'id', root: 'data', totalproperty: 'total', fields: ['id','stateid','name'] }) ,triggeraction:'all' ,mode:'local' ,lastquery:'' }] }); the state combo box is declared on lines 9 to 38. the city combo box is declared on lines 40 to 55. note that only state combo store is loaded when we load the page, as we can see at the line 15 (autoload:true). the state combo box has the select event listener that, when executed, reloads the data for cities store (passes stateid as parameter) based on the currently selected state. you can see it on lines 24 to 38. cities combo has lastquery:”" . this is to fool internal combo filtering routines on the first page load. the cities combo just thinks that it has already been expanded once. you can download the complete project from my github repository: i used eclipse ide + tomcat 7 to develop this sample project. references: http://www.sencha.com/learn/tutorial:linked_combos_tutorial_for_ext_2 from http://loianegroner.com/2010/10/tutorial-linkedcascading-extjs-combo-boxes-using-spring-mvc-3-and-hibernate-3-5/
October 20, 2010
by Loiane Groner
· 32,592 Views · 1 Like
  • Previous
  • ...
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×