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
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Latest Articles - DZone

article thumbnail
Application Logging: What, When, How
logging is a fundamental part of applications. every application has a varying flavor of logging mechanism. a well designed logging system is a huge utility for system administrators and developers, especially the support team. logs save many valuable hours for both the support team or developers. as users execute programs at the front end, the system invisibly builds a vault of event information (log entries) for system administrators and the support team. after stating its value, let’s try to figure out the logging requirements for an application. java has a standard logging api in its new versions (java.util.logging). log4j is also a well-known library for logging. we implemented a transparent “logging service” in our application framework. you may prefer some kind of logging implementations but there are some other important questions you have to answer in your application design which are what to log, when to log, how much to log, how to control logging and how correlate it with your exception system. what to log some application exceptions should be logged: why not log all exceptions? some exceptions are managed exceptions which are thrown by application as a warning or as a validation error to the user. if all validation errors or application exceptions are included in logs, the logs will lose their usefulness. it would contain many entries, it makes it hard to reach valuable entries. here, we should discriminate exceptions if they should be logged. we used a loggable mark interface to determine if it is included in logs. another best practice is to have a single global exception handler. in this way, application developers don’t worry about logging of any exception they generate. a single exception handler means a single unified and neat exception logging mechanism. some application events should be logged: for major components of an application we may log lifecycle events like start, stop and restart. some security-related events may be logged such as unauthorized url access attempts, user logins etc. some resource thresholds may be exceeded and should also be logged. some application states should be logged: in some codes, we should ask that “what could go wrong here in this code”. if this state occurs, we may throw an exception or log it (if we don’t want to interrupt current process) with some levels like error, warning or information. for example if a connection is normally released while it is uncommitted, that info may be logged as uncommitted connection release that points some application code problems. some debug information may be logged: in some applications, you may have some errors and can’t find why this is happening. you may add some debug logs into your code and redeploy it to diagnose the problem. some chronic bugs deserve debug traces which can’t be detected in development environment. executed sqls may be logged: in some conditions, we may want to get the sql statement executed by an application. we should easily switch logging on without start/stop of system. let’s say user complain about wrong report result when executing a report. if we don’t have a clue about that we may log sql and trace it. user http requests may be logged: we may need what is coming from the user with full parameter details. to achieve this kind of logging we have to plug a log service in servlets and jsp pages. executing threads may be logged: i mentioned a blackbox implementation in our applications in one of my previous posts. you may log executing thread information to that black box to figure out what may go wrong in a system crash. javascript errors may be logged: this may be considered same with first item but its implementations totally differs. you need to have a global javascript exception handler. in the handler, you submit javascript error with ajax to log on the server (assuming it is not an ajax error). some best practices as i said above, the exception handling system is an important plug point for logging. in all our servlets and jsps, the main code blocks have the following structure to enable global exception handling. this standard eliminates the work of logging exceptions by developers (transparent unified logging): try { } catch(exception e) { globalhandler.handleexception(e); } we named “log medium” to mean where to store log entries but in java logging api it is called handlers. for some type of logs, database logs are handy since you can run powerful sql queries against log table which is merely possible in files. to assign log messages to the appropriate log levels is also important. otherwise some wrong alerts would mislead system administrators. we used system.err stream for application-level logging which is same place with e.printstacktrace() which may be printed with our global handler log entry at the same time. we wouldn’t need all exception’s stack trace but some may be very useful to see where the root of the problem (i.e. stackoverflowexception). when logging exceptions we used following format. some articles recommends that we’d better to include problem failover suggestion but i think this information should be given to the user not included in the logs. logs are rarely read but exceptions are in front of users. log entry should answer following questions: who (username) , when (timestamp) , where (context, servletorpage,database) , what (command) , result (exception) [errorhandlername] username: userabc databasename: abc timestamp: 15.07.2009 13:02:08 context:servlet page: /prod/sales/salesorders.jsp window: windwname command: savesalesorder exception: shortdescriptionofexception exceptionstacktracehere in a clustered environment, logging should be considered. we separated same type of log files with a cluster node name suffix to the file name. otherwise, concurrent log writes may lead to some problems. system_node01.log system_node02.log as a last item, logging may be a very interesting performance killer. if applications begin to log a lot, application performance may severely fall down. i have a real life story for that. once we had forgotten to include an image file in deployment package. it was being used in every page. when we started system after installment, page response was so slow. log files seem small enough that may not incur problem. after, opening and reading log files, we realized that log frequency (stating image is missing) was high and that was causing the problem. in conclusion, your log file size and log writing frequency should be small.
September 1, 2009
by Adam Brown
· 79,579 Views · 2 Likes
article thumbnail
Java Performance Tuning, Profiling, and Memory Management
Get a perspective on the aspects of JVM internals, controls, and switches that can be used to optimize your Java application.
September 1, 2009
by Vikash Ranjan
· 257,852 Views · 17 Likes
article thumbnail
JPA Performance, Don't Ignore the Database
Good Database schema design is important for performance. One of the most basic optimizations is to design your tables to take as little space on the disk as possible , this makes disk reads faster and uses less memory for query processing. Data Types You should use the smallest data types possible, especially for indexed fields. The smaller your data types, the more indexes (and data) can fit into a block of memory, the faster your queries will be. Normalization Database Normalization eliminates redundant data, which usually makes updates faster since there is less data to change. However a Normalized schema causes joins for queries, which makes queries slower, denormalization speeds retrieval. More normalized schemas are better for applications involving many transactions, less normalized are better for reporting types of applications. You should normalize your schema first, then de-normalize later. Applications often need to mix the approaches, for example use a partially normalized schema, and duplicate, or cache, selected columns from one table in another table. With JPA O/R mapping you can use the @Embedded annotation for denormalized columns to specify a persistent field whose @Embeddable type can be stored as an intrinsic part of the owning entity and share the identity of the entity. Database Normalization and Mapping Inheritance Hiearchies The Class Inheritance hierarchy shown below will be used as an example of JPA O/R mapping. In the Single table per class mapping shown below, all classes in the hierarchy are mapped to a single table in the database. This table has a discriminator column (mapped by @DiscriminatorColumn), which identifies the subclass. Advantages: This is fast for querying, no joins are required. Disadvantages: wastage of space since all inherited fields are in every row, a deep inheritance hierarchy will result in wide tables with many, some empty columns. In the Joined Subclass mapping shown below, the root of the class hierarchy is represented by a single table, and each subclass has a separate table that only contains those fields specific to that subclass. This is normalized (eliminates redundant data) which is better for storage and updates. However queries cause joins which makes queries slower especially for deep hierachies, polymorphic queries and relationships. In the Table per Class mapping (in JPA 2.0, optional in JPA 1.0), every concrete class is mapped to a table in the database and all the inherited state is repeated in that table. This is not normlalized, inherited data is repeated which wastes space. Queries for Entities of the same type are fast, however polymorphic queries cause unions which are slower. Know what SQL is executed You need to understand the SQL queries your application makes and evaluate their performance. Its a good idea to enable SQL logging, then go through a use case scenario to check the executed SQL. Logging is not part of the JPA specification, With EclipseLink you can enable logging of SQL by setting the following property in the persistence.xml file: With Hibernate you set the following property in the persistence.xml file: Basically you want to make your queries access less data, is your application retrieving more data than it needs, are queries accessing too many rows or columns? Is the database query analyzing more rows than it needs? Watch out for the following: queries which execute too often to retrieve needed data retrieving more data than needed queries which are too slow you can use EXPLAIN to see where you should add indexes With MySQL you can use the slow query log to see which queries are executing slowly, or you can use the MySQL query analyzer to see slow queries, query execution counts, and results of EXPLAIN statements. Understanding EXPLAIN For slow queries, you can precede a SELECT statement with the keyword EXPLAIN to get information about the query execution plan, which explains how it would process the SELECT, including information about how tables are joined and in which order. This helps find missing indexes early in the development process. You should index columns that are frequently used in Query WHERE, GROUP BY clauses, and columns frequently used in joins, but be aware that indexes can slow down inserts and updates. Lazy Loading and JPA With JPA many-to-one and many-to-many relationships lazy load by default, meaning they will be loaded when the entity in the relationship is accessed. Lazy loading is usually good, but if you need to access all of the "many" objects in a relationship, it will cause n+1 selects where n is the number of "many" objects. You can change the relationship to be loaded eagerly as follows : However you should be careful with eager loading which could cause SELECT statements that fetch too much data. It can cause a Cartesian product if you eagerly load entities with several related collections. If you want to override the LAZY fetch type for specific use cases, you can use Fetch Join. For example this query would eagerly load the employee addresses: In General you should lazily load relationships, test your use case scenarios, check the SQL log, and use @NameQueries with JOIN FETCH to eagerly load when needed. Partitioning The main goal of partitioning is to reduce the amount of data read for particular SQL operations so that the overall response time is reduced Vertical Partitioning splits tables with many columns into multiple tables with fewer columns, so that only certain columns are included in a particular dataset, with each partition including all rows. Horizontal Partitioning segments table rows so that distinct groups of physical row-based datasets are formed. All columns defined to a table are found in each set of partitions. An example of horizontal partitioning might be a table that contains historical data being partitioned by date. Vertical Partitioning In the example of vertical partitioning below a table that contains a number of very wide text or BLOB columns that aren't referenced often is split into two tables with the most referenced columns in one table and the seldom-referenced text or BLOB columns in another. By removing the large data columns from the table, you get a faster query response time for the more frequently accessed Customer data. Wide tables can slow down queries, so you should always ensure that all columns defined to a table are actually needed. The example below shows the JPA mapping for the tables above. The Customer data table with the more frequently accessed and smaller data types is mapped to the Customer Entity, the CustomerInfo table with the less frequently accessed and larger data types is mapped to the CustomerInfo Entity with a lazily loaded one to one relationship to the Customer. Horizontal Partitioning The major forms of horizontal partitioning are by Range, Hash, Hash Key, List, and Composite. Horizontal partitioning can make queries faster because the query optimizer knows what partitions contain the data that will satisfy a particular query and will access only those necessary partitions during query execution. Horizontal Partitioning works best for large database Applications that contain a lot of query activity that targets specific ranges of database tables. Hibernate Shards Partitioning data horizontally into "Shards" is used by google, linkedin, and others to give extreme scalability for very large amounts of data. eBay "shards" data horizontally along its primary access path. Hibernate Shards is a framework that is designed to encapsulate support for horizontal partitioning into the Hibernate Core. Caching JPA Level 2 caching avoids database access for already loaded entities, this makes reading frequently accessed unmodified entities faster, however it can give bad scalability for frequent or concurrently updated entities. You should configure L2 caching for entities that are: read often modified infrequently Not critical if stale You should also configure L2 (vendor specific) caching for maxElements, time to expire, refresh... References and More Information: JPA Best Practices presentation MySQL for Developers Article MySQL for developers presentation MySQL for developers screencast Keeping a Relational Perspective for Optimizing Java Persistence Java Persistence with Hibernate Pro EJB 3: Java Persistence API Java Persistence API 2.0: What's New ? High Performance MySQL book Pro MySQL, Chapter 6: Benchmarking and Profiling EJB 3 in Action sharding the hibernate way JPA Caching Best Practices for Large-Scale Web Sites: Lessons from eBay
August 31, 2009
by Carol McDonald
· 41,839 Views · 1 Like
article thumbnail
JPA Caching
JPA has 2 levels of caching. The first level of caching is the persistence context. The JPA Entity Manager maintains a set of Managed Entities in the Persistence Context. The Entity Manager guarantees that within a single Persistence Context, for any particular database row, there will be only one object instance. However the same entity could be managed in another User's transaction, so you should use either optimistic or pessimistic locking as explained in JPA 2.0 Concurrency and locking The code below shows that a find on a managed entity with the same id and class as another in the same persistence context , will return the same instance. @Stateless public ShoppingCartBean implements ShoppingCart { @PersistenceContext EntityManager entityManager; public OrderLine createOrderLine(Product product,Order order) { OrderLine orderLine = new OrderLine(order, product); entityManager.persist(orderLine); //Managed OrderLine orderLine2 =entityManager.find(OrderLine, orderLine.getId())); (orderLine == orderLine2) // TRUE return (orderLine); } } The diagram below shows the life cycle of an Entity in relation to the Persistent Context. The code below illustrates the life cycle of an Entity. A reference to a container managed EntityManager is injected using the persistence context annotation. A new order entity is created and the entity has the state of new. Persist is called, making this a managed entity. because it is a stateless session bean it is by default using container managed transactions , when this transaction commits , the order is made persistent in the database. When the orderline entity is returned at the end of the transaction it is a detached entity. The Persistence Context can be either Transaction Scoped-- the Persistence Context 'lives' for the length of the transaction, or Extended-- the Persistence Context spans multiple transactions. With a Transaction scoped Persistence Context, Entities are "Detached" at the end of a transaction. As shown below, to persist the changes on a detached entity, you call the EntityManager's merge() operation, which returns an updated managed entity, the entity updates will be persisted to the database at the end of the transaction. An Extended Persistence Context spans multiple transactions, and the set of Entities in the Persistence Context stay Managed. This can be useful in a work flow scenario where a "conversation" with a user spans multiple requests. The code below shows an example of a Stateful Session EJB with an Extended Persistence Context in a use case scenario to add line Items to an Order. After the Order is persisted in the createOrder method, it remains managed until the EJB remove method is called. In the addLineItem method , the Order Entity can be updated because it is managed, and the updates will be persisted at the end of the transaction. The example below contrasts updating the Order using a transaction scoped Persistence Context verses an extended Persistence context. With the transaction scoped persistence context, an Entity Manager find must be done to look up the Order, this returns a Managed Entity which can be updated. With the Extended Persistence Context the find is not necessary. The performance advantage of not doing a database read to look up the Entity, must be weighed against the disadvantages of memory consumption for caching, and the risk of cached entities being updated by another transaction. Depending on the application and the risk of contention among concurrent transactions this may or may not give better performance / scalability. JPA second level (L2) caching JPA second level (L2) caching shares entity state across various persistence contexts. JPA 1.0 did not specify support of a second level cache, however, most of the persistence providers provided support for second level cache(s). JPA 2.0 specifies support for basic cache operations with the new Cache API, which is accessible from the EntityManagerFactory, shown below: If L2 caching is enabled, entities not found in persistence context, will be loaded from L2 cache, if found. The advantages of L2 caching are: avoids database access for already loaded entities faster for reading frequently accessed unmodified entities The disadvantages of L2 caching are: memory consumption for large amount of objects Stale data for updated objects Concurrency for write (optimistic lock exception, or pessimistic lock) Bad scalability for frequent or concurrently updated entities You should configure L2 caching for entities that are: read often modified infrequently Not critical if stale You should protect any data that can be concurrently modified with a locking strategy: Must handle optimistic lock failures on flush/commit configure expiration, refresh policy to minimize lock failures The Query cache is useful for queries that are run frequently with the same parameters, for not modified tables. The EclipseLink JPA persistence provider caching Architecture The EclipseLink caching Architecture is shown below. Support for second level cache in EclipseLink is turned on by default, entities read are L2 cached. You can disable the L2 cache. EclipseLink caches entities in L2, Hibernate caches entity id and state in L2. You can configure caching by Entity type or Persistence Unit with the following configuration parameters: Cache isolation, type, size, expiration, coordination, invalidation,refreshing Coordination (cluster-messaging) Messaging: JMS, RMI, RMI-IIOP, … Mode: SYNC, SYNC+NEW, INVALIDATE, NONE The example below shows configuring the L2 cache for an entity using the @Cache annotation The Hibernate JPA persistence provider caching Architecture The Hibernate JPA persistence provider caching architecture is different than EclipseLink: it is not configured by default, it does not cache enities just id and state, and you can plug in different L2 caches. The diagram below shows the different L2 cache types that you can plug into Hibernate. The configuration of the cache depends on the type of caching plugged in. The example below shows configuring the hibernate L2 cache for an entity using the @Cache annotation For More Information: Introducing EclipseLink EclipseLink JPA User Guide Hibernate Second Level Cache Speed Up Your Hibernate Applications with Second-Level Caching Hibernate caching Java Persistence API 2.0: What's New ? Beginning Java™ EE 6 Platform with GlassFish™ 3 Pro EJB 3: Java Persistence API (JPA 1.0)
August 24, 2009
by Carol McDonald
· 80,946 Views · 39 Likes
article thumbnail
Extracting Filename (without Extension) In Ruby
Shortest, rock-solid idiom for removing the extension, without removing the preceding path: fname.chomp(File.extname(fname)) Best idiom if you are removing the path also: File.basename(fname, '.*')
August 23, 2009
by Snippets Manager
· 4,212 Views
article thumbnail
JPA Implementation Patterns: Lazy Loading
Model your complete database with all its relations with this JPA pattern for lazy loading.
August 19, 2009
by Vincent Partington
· 120,586 Views · 6 Likes
article thumbnail
Spring Integration: A Hands-On Tutorial, Part 1
This tutorial is the first in a two-part series on Spring Integration. In this series we're going to build out a lead management system based on a message bus that we implement using Spring Integration. Our first tutorial will begin with a brief overview of Spring Integration and also just a bit about the lead management domain. After that we'll build our message bus. The second tutorial continues where the first leaves off and builds the rest of the bus. I’ve written the sample code for this tutorial as a Maven 2 project. I’m using Java 5, Spring Integration 1.0.3 and Spring 2.5.6. The code also works for Java 6. I've used Maven profiles to isolate the dependencies you’ll need if you’re running Java 5. The tutorials assume that you're comfortable with JEE, the core Spring framework and Maven 2. Also, Eclipse users may find the m2eclipse plug-in helpful. To complete the tutorial you'll need an IMAP account, and you'll also need access to an SMTP server. Let's begin with an overview of Spring Integration. A bird's eye view of Spring Integration Spring Integration is a framework for implementing a dynamically configurable service integration tier. The point of this tier is to orchestrate independent services into meaningful business solutions in a loosely-coupled fashion, which makes it easy to rearrange things in the face of changing business needs. The service integration tier sits just above the service tier as shown in figure 1. Following the book Enterprise Integration Patterns by Gregor Hohpe and Bobby Woolf (Addison-Wesley), Spring Integration adopts the well-known pipes and filters architectural style as its approach to building the service integration layer. Abstractly, filters are information-processing units (any type of processing—doesn’t have to be information filtering per se), and pipes are the conduits between filters. In the context of integration, the network we’re building is a messaging infrastructure—a so-called message bus—and the pipes and filters and called message channels and message endpoints, respectively. The network carries messages from one endpoint to another via channels, and the message is validated, routed, split, aggregated, resequenced, reformatted, transformed and so forth as the different endpoints process it. Figure 1. The service integration tier orchestrates the services below it. That should give you enough technical context to work through the tutorial. Let’s talk about the problem domain for our sample integration, which is enrollment lead management in an online university setting. Lead management overview In many industries, such as the mortgage industry and for-profit education, one important component of customer relationship management (CRM) is managing sales leads. This is a fertile area for enterprise integration because there are typically multiple systems that need to play nicely together in order to pull the whole thing off. Examples include front-end marketing/lead generation websites, external lead vendor systems, intake channels for submitted leads, lead databases, e-mail systems (e.g., to accept leads, to send confirmation e-mails), lead qualification systems, sales systems and potentially others. This tutorial and the next use Spring Integration to integrate several of systems of the kind just mentioned into an overall lead management capability for a hypothetical online university. Specifically we’ll integrate the following: • a CRM system that allows campus and call center staff to create leads directly, as they might do for walk-in or phone-in leads • a Request For Information (RFI) form on a lead generation ("lead gen") marketing website • a legacy e-mail based RFI channel • an external CRM that the international enrollment staff uses to process international leads • confirmation e-mails Figure 2 shows what it will look like when we’re done with both tutorials. For now focus on the big picture rather than the details. Figure 2. This is the lead management system we'll build. For this first tutorial we're simply going to establish the base staff interface, the (dummy) backend service that saves leads to a database, and confirmation e-mails. The second tutorial will deal with lead routing, web-based RFIs and e-mail-based RFIs. Let's dive in. We’ll begin with the basic lead creation page in the CRM and expand out from there. Building the core components [You can download the source code for this section of the tutorial here] We’re going to start by creating a lead creation HTML form for campus and call center staff. That way, if walk-in or phone-in leads express an interest, we can get them into the system. This is something that might appear as a part of a lead management module in a CRM system, as shown in figure 3. Figure 3. We'll build our lead management module with integration in mind from the beginning. Because we’re interested in the integration rather than the actual app features, we’re not really going to save the lead to the database. Instead we’ll just call a createLead() method against a local LeadService bean and leave it at that. But we will use Spring Integration to move the lead from the form to the service bean. Our first stop will be the domain model. DZone readers get 30% off Spring in Practice by Willie Wheeler and John Wheeler. Use code dzone30 when checking out with any version of the book at www.manning.com. Create the domain model We’ll need a domain object for leads, so listing 1 shows the one we’ll use. It’s not an industrial-strength representation, but it will do for the purposes of the tutorial. Listing 1. Lead.java, a basic domain object for leads. package crm.model;... other imports ...public class Lead { private static DateFormat dateFormat = new SimpleDateFormat(); private String firstName; private String middleInitial; private String lastName; private String address1; private String address2; ... other fields ... public Lead() { } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } ... other getters and setters, and a toString() method ...} There is nothing special happening here at all. So far the Lead class is just a bunch of getters and setters. You can see the full code listing in the download. If you thought that was underwhelming, just wait until you see the LeadServiceImpl service bean in listing 2. Listing 2. LeadServiceImpl.java, a dummy service bean. package crm.service;import java.util.logging.Logger;import org.springframework.stereotype.Service;import crm.model.Lead;@Service("leadService")public class LeadServiceImpl implements LeadService { private static Logger log = Logger.getLogger("global"); public void createLead(Lead lead) { log.info("Creating lead: " + lead); } This is just a dummy bean. In real life we’d save the lead to a database. The bean implements a basic LeadService interface that we've suppressed here, but it's available in the code download. Now that we have our domain model, let’s use Spring Integration to create a service integration tier above it. Create the service integration tier If you look back at figure 3, you’ll see that the CRM app pushes lead data to the service bean by way of a channel called newLeadChannel. While it’s possible for the CRM app to push messages onto the channel directly, it’s generally more desirable to keep the systems you’re integrating decoupled from the underlying messaging infrastructure, such as channels. That allows you to configure service orchestrations dynamically instead of having to go into the code. Spring Integration supports the Gateway pattern (described in the aforementioned Enterprise Integration Patterns book), which allows an application to push messages onto the message bus without knowing anything about the messaging infrastructure. Listing 3 shows how we do this. Listing 3. LeadGateway.java, a gateway offering access to the messaging system. package crm.integration.gateways;import org.springframework.integration.annotation.Gateway;import crm.model.Lead;public interface LeadGateway { @Gateway(requestChannel = "newLeadChannel") void createLead(Lead lead);} We are of course using the Spring Integration @Gateway annotation to map the method call to the newLeadChannel, but gateway clients don’t know that. Spring Integration will use this interface to create a dynamic proxy that accepts a Lead instance, wraps it with an org.springframework.integration.core.Message, and then pushes the Message onto the newLeadChannel. The Lead instance is the Message body, or payload, and Spring Integration wraps the Lead because only Messages are allowed on the bus. We need to wire up our message bus. Figure 4 shows how to do that with an application context configuration file. Listing 4. /WEB-INF/applicationContext-integration.xml message bus definition. The first thing to notice here is that we've made the Spring Integration namespace our default namespace instead of the standard beans namespace. The reason is that we're using this configuration file strictly for Spring Integration configuration, so we can save some keystrokes by selecting the appropriate namespace. This works pretty nicely for some of the other Spring projects as well, such as Spring Batch and Spring Security. In this configuration we've created the three messaging components that we saw in figure 3. First, we have an incoming lead gateway to allow applications to push leads onto the bus. We simply reference the interface from listing 3; Spring Integration takes care of the dynamic proxy. Next we create a publish/subscribe ("pub-sub") channel called newLeadChannel. This is the channel that the @Gateway annotation referenced in listing 3. A pub-sub channel can publish a message to multiple endpoints simultaneously. For now we have only one subscriber—a service activator—but we already know we're going to have others, so we may as well make this a pub-sub channel. The service activator is an endpoint that allows us to bring our LeadServiceImpl service bean onto the bus. We're injecting the newLeadChannel into the input end of the service activator. When a message appears on the newLeadChannel, the service activator will pass its Lead payload to the leadService bean's createLead() method. Stepping back, we've almost implemented the design described by figure 3. The only part that remains is the lead creation frontend, which we'll address right now. Create the web tier Our user interface for creating new leads will be a web-based form that we implement using Spring Web MVC. The idea is that enrollment staff at campuses or call centers might use such an interface to handle walk-in or phone-in traffic. Listing 5 shows our simple @Controller. Listing 5. LeadController.java, a @Controller to allow staff to create leads package crm.web;import java.util.Date;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import crm.integration.gateways.LeadGateway;import crm.model.Country;import crm.model.Lead;@Controllerpublic class LeadController { @Autowired private LeadGateway leadGateway; @RequestMapping(value = "/lead/form.html", method = RequestMethod.GET) public void getForm(Model model) { model.addAttribute(Country.getCountries()); model.addAttribute(new Lead()); } @RequestMapping(value = "/lead/form.html", method = RequestMethod.POST) public String postForm(Lead lead) { lead.setDateCreated(new Date()); leadGateway.createLead(lead); return "redirect:form.html?created=true"; } This isn't an industrial-strength controller as it doesn't do HTTP parameter whitelisting (for example, via an @InitBinder method) and form validation, both of which you would expect from a real implementation. But the main pieces from a Spring Integration perspective are here. We're autowiring the gateway into the @Controller, and we have methods for serving up the empty form and for processing the submitted form. The getForm() method references a Countries class that we've suppressed (it's in the code download); it just puts a list of countries on the model so the form can present a Country field to the staff member. The postForm() method invokes the createLead() method on the gateway. This will pass the Lead to the dynamic proxy LeadGateway implementation, which in turn will wrap the Lead with a Message and then place the Message on the newLeadChannel. There are a few other configuration files you will need to put in place, including web.xml, main-servlet.xml and applicationContext.xml. There's also a JSP for the web form. As none of these relates directly to Spring Integration, we won't treat them here. Please see the code download for details. With that, we've established a baseline system. To try it out, run mvn jetty:run against crm/pom.xml and point your browser at http://localhost:8080/crm/main/lead/form.html You should see a very basic-looking web form for entering lead information. Enter some user information (it doesn't matter what you enter—recall that we don't have any form validation) and press Submit. The console should report that LeadServiceImpl.createLead() created a lead. Congratulations! Even though we now have a working system, it isn't very interesting. From here on out (this tutorial and the next) we'll be adding some common features to make the lead management system more capable. Our first addition will be confirmation e-mails; the next tutorial will present further additions. Adding confirmation e-mails [The source for this section is available here] After an enrollment advisor (or some other staff member) creates a lead in the system, we want to send the lead an e-mail letting him know that that's happened. Actually—and this is a critical point—we really don't care how the lead was created. Anytime a lead appears on the newLeadChannel, we want to fire off a confirmation e-mail. I'm making the distinction because it points to an important aspect of the message bus: it allows us to control lead processing code centrally instead of having to chase it down in a bunch of different places. Right now there's only one way to create leads, but figure 2 revealed that we'll be adding others. No matter how many we add, they'll all result in sending a confirmation e-mail out to the lead. Figure 4 shows the new bit of plumbing we're going to add to our message bus. Figure 4. Send a confirmation e-mail when creating a lead. To do this, we're going to need to make a few changes to the configuration and code. POM changes First we need to update the POM. Here's a summary of the changes; see the code download for details: • Add a JavaMail dependency to the Jetty plug-in. • Add an org.springframework.context.support dependency. • Add a spring-integration-mail dependency. • Set the mail.version property. These changes will allow us to use JavaMail. Expose JavaMail sessions through JNDI We'll also need to add a /WEB-INF/jetty-env.xml configuration to make our JavaMail sessions available via JNDI. Once again, see the code download for details. I've included a /WEB-INF/jetty-env.xml.sample configuration for your convenience. As mentioned previously, you'll need access to an SMTP server. Besides creating jetty-env.xml, we'll need to update applicationContext.xml. Listing 6 shows the changes we need so we can use JavaMail and SMTP. Listing 6. /WEB-INF/applicationContext.xml changes supporting JavaMail and SMTP The changes expose JavaMail sessions as a JNDI resource. We've declared the jee namespace and its schema location, configured the JNDI lookup, and created a JavaMailSenderImpl bean that we'll use for sending mail. We won't need any domain model changes to generate confirmation e-mails. We will however need to create a bean to back our new transformer endpoint. Service integration tier changes First, recall from figure 4 that the newLeadChannel feeds into a LeadToEmailTransformer endpoint. This endpoint takes a lead as an input and generates a confirmation e-mail as an output, and the e-mail gets pipes out to an SMTP transport. In general, transformers transform given inputs into desired outputs. No surprises there. Figure 4 is slightly misleading since it's actually the POJO itself that we're going to call LeadToEmailTransformer; the endpoint is really just a bean adapter that the messaging infrastructure provides so we can place the POJO on the message bus. Listing 7 presents the LeadToEmailTransformer POJO. Listing 7. LeadToEmailTransformer.java, a POJO to generate confirmation e-mails package crm.integration.transformers;import java.util.Date;import java.util.logging.Logger;import org.springframework.integration.annotation.Transformer;import org.springframework.mail.MailMessage;import org.springframework.mail.SimpleMailMessage;import crm.model.Lead;public class LeadToEmailTransformer { private static Logger log = Logger.getLogger("global"); private String confFrom; private String confSubj; private String confText; ... getters and setters for the fields ... @Transformer public MailMessage transform(Lead lead) { log.info("Transforming lead to confirmation e-mail: " + lead); String leadFullName = lead.getFullName(); String leadEmail = lead.getEmail(); MailMessage msg = new SimpleMailMessage(); msg.setTo(leadFullName == null ? leadEmail : leadFullName + " <" + leadEmail + ">"); msg.setFrom(confFrom); msg.setSubject(confSubj); msg.setSentDate(new Date()); msg.setText(confText); log.info("Transformed lead to confirmation e-mail: " + msg); return msg; } Again, LeadToEmailTransformer is a POJO, so we use the @Transformer annotation to select the method that's performing the transformation. We use a Lead for the input and a MailMessage for the output, and perform a simple transformation in between. When defining backing beans for the various Spring Integration filters, it's possible to specify a Message as an input or an output. That is, if we want to deal with the messages themselves rather than their payloads, we can do that. (Don't confuse the MailMessage in listing 7 with a Spring Integration message; MailMessage represents an e-mail message, not a message bus message.) We might do that in cases where we want to read or manipulate message headers. In this tutorial we don't need to do that, so our backing beans just deal with payloads. Now we'll need to build out our message bus so that it looks like figure 4. We do this by updating applicationContext-integration.xml as shown in listing 8. Listing 8. /WEB-INF/applicationContext-integration.xml updates to support confirmation e-mails The property-placeholder configuration loads the various ${...} properties from a properties file; see /crm/src/main/resources/applicationContext.properties in the code download. You don't have to change anything in the properties file. The transformer configuration brings the LeadToEmailTransformer bean into the picture so it can transform Leads that appear on the newLeadChannel into MailMessages that it puts on the confEmailChannel. As a side note, the p namespace way of specifying bean properties doesn't seem to work here (I assume it's a bug: http://jira.springframework.org/browse/SPR-5990), so I just did it the more verbose way. The channel definition defines a point-to-point channel rather than a pub-sub channel. That means that only one endpoint can pull messages from the channel. Finally we have an outbound-channel-adapter that grabs MailMessages from the confEmailChannel and then sends them using the referenced mailSender, which we defined in listing 6. That's it for this section. We should have working confirmation e-mails. Restart your Jetty instance and go again to http://localhost:8080/crm/main/lead/form.html Fill it out and provide your real e-mail address in the e-mail field. A few moments after submitting the form you should receive a confirmation e-mail. If you don't see it, you might check your SMTP configuration in jetty-env.xml, or else check your spam folder. Summary In this tutorial we've taken our first steps toward developing an integrated lead management system. Though the current bus configuration is simple, we've already seen some key Spring Integration features, including • support for the Gateway pattern, allowing us to connect apps to the message bus without knowing about messages • point-to-point and pub-sub channels • service activators to allow us to place service beans on the bus • message transformers • outbound SMTP channel adapters to allow us to send e-mail The second tutorial will continue elaborating what we've developed here, demonstrating the use of several additional Spring Integration features, including • message routers (including content-based message routers) • outbound web service gateways for sending SOAP messages • inbound HTTP adapters for collecting HTML form data from external systems • inbound e-mail channel adapters (we'll use IMAP IDLE, though POP and IMAP are also possible) for processing incoming e-mails Enjoy, and stay tuned. Willie is a solutions architect with 12 years of Java development experience. He and his brother John are coauthors of the upcoming book Spring in Practice by Manning Publications (www.manning.com/wheeler/). Willie also publishes technical articles (including many on Spring) to wheelersoftware.com/articles/.
August 18, 2009
by Willie Wheeler
· 249,540 Views · 3 Likes
article thumbnail
Urlencode/urldecode As MySQL Stored Functions
DELIMITER ; DROP FUNCTION IF EXISTS multiurldecode; DELIMITER | CREATE FUNCTION multiurldecode (s VARCHAR(4096)) RETURNS VARCHAR(4096) DETERMINISTIC CONTAINS SQL BEGIN DECLARE pr VARCHAR(4096) DEFAULT ''; IF ISNULL(s) THEN RETURN NULL; END IF; REPEAT SET pr = s; SELECT urldecode(s) INTO s; UNTIL pr = s END REPEAT; RETURN s; END; | DELIMITER ;
August 18, 2009
by Snippets Manager
· 13,792 Views · 5 Likes
article thumbnail
Using SelfPopulatingCache in Ehcache
Often you will notice that Ehcache is used mostly like a tool that implements highly configurable maps. Sometimes developers configure time-to-live properties, or make use of disk-store functionality, but you can rarely meet someone who has cache population/eviction process that makes sense. In the perfect world I would expect cache to be a universal pool. I request a value for a key and would like to get it whenever it is possible and as fast as possible with just one line of code. But in reality I usually can see huge cache population code on the application startup, daemon threads that update caches in eternal loop and numerous “ifs” around cache.get() calls. In my strive to the perfect world I’ve discovered a SelfPopulatingCache class in Ehcache. In this article I will describe how using SelfPopulatingCache class one can implement a cache with self creating objects with optional auto-updating. In some way this example is an implementation of ideas mentioned in Ehcache documentation. Example What you will see down here: A Reader that fetches an object from cache 5 times every 0.5 seconds. Behind scenes cache will create a new object if there is no such object is there in cache for a key requested. A daemon thread will trigger cache refresh every 2 seconds. The most important class in this example is ExampleCacheProvider. package com.blogspot.mikler.java; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Ehcache; import net.sf.ehcache.constructs.blocking.SelfPopulatingCache; import net.sf.ehcache.constructs.blocking.CacheEntryFactory; public class ExampleCacheProvider { private CacheManager cacheManager; private CacheEntryFactory updatingFactory; public SelfPopulatingCache selfPopulatingCache; public ExampleCacheProvider() throws Exception { cacheManager = CacheManager.create(); Ehcache originalCache = cacheManager.getCache("com.blogspot.mikler.java.cache"); final String cacheType = System.getProperty("com.blogspot.mikler.java.cache.factory"); if (cacheType == null || cacheType.equals("create")){ updatingFactory = new ExampleCacheEntryFactory(); } else { updatingFactory = new ExampleUpdatingCacheEntryFactory(); } selfPopulatingCache = new SelfPopulatingCache(originalCache, updatingFactory); //chache refresh thread Thread updatingThread = new Thread(){ public void run() { while (true){ System.out.println("!!!!! Doing refresh !!!!!"); selfPopulatingCache.refresh(); try { Thread.sleep(2000); } catch (InterruptedException e) { System.out.println("Interrupted"); } } } }; updatingThread.setDaemon(true); updatingThread.start(); } public Ehcache getCache(){ return selfPopulatingCache; } } What it does is creating simple Ehcache (original cache) and wrapping it with SelfPopulatingCache (selfPopulatingCache). We can use this class the same way as CacheManager, so one can consider extending CacheManager, but to keep it simple here we'll stick to this kind of cache source. While wrapping we specify updatingFactory, which can be set to one of two options: ExampleCacheEntryFactory (line 19) and ExampleUpdatingCacheEntryFactory(line 21). For the purposes of this example the choice between this two options is done based on the “com.blogspot.mikler.java.cache.factory” system property value. The difference between this two is that ExampleCacheEntryFactory implements CacheEntryFactory interface, while ExampleUpdatingCacheEntryFactory extends ExampleCacheEntryFactory and implements UpdatingCacheEntryFactory. The difference between using each of this options is explained later on. Meanwhile here is the code of both classes. package com.blogspot.mikler.java; import net.sf.ehcache.constructs.blocking.CacheEntryFactory; public class ExampleCacheEntryFactory implements CacheEntryFactory { public Object createEntry(Object key) throws Exception { System.out.println("++++++creating entry for key = " + key); return new StringBuffer(Long.toString(Math.round(100*Math.random())) + key+"0"); } } package com.blogspot.mikler.java; import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory; public class ExampleUpdatingCacheEntryFactory extends ExampleCacheEntryFactory implements UpdatingCacheEntryFactory { public void updateEntryValue(Object key, Object value) throws Exception { System.out.println("~~~~~~UPDATING entry for key = " + key); final StringBuffer stringBuffer = (StringBuffer) value; stringBuffer.append(stringBuffer.length()); } } As you can see in this example as cache element’s key string used, while StringBuffer is used as a value. In createEntry() method in ExampleCacheEntryFactory StringBuffer is created with leading random number. While in updateEntryValue() method of ExampleUpdatingCacheEntryFactory existing StringBuffer length is appended to the buffer itself. And finally, here goes our Reader main class. It fetches our wrapped cache, get’s value for “foo” key from it and stores it into final local variable fooOriginalBuffer, that is never changed late in Reader’s code. Then it starts doing 5 iterations of getting value for “foo” key from cache, displaying debug info and stats, and sleeping for one second. The code is simple as this. package com.blogspot.mikler.java; import net.sf.ehcache.Ehcache; public class Reader { private ExampleCacheProvider exampleCacheProvider; public Reader(ExampleCacheProvider exampleCacheProvider) { this.exampleCacheProvider = exampleCacheProvider; } public void run(){ Ehcache cache = exampleCacheProvider.getCache(); final StringBuffer fooOriginalBuffer = (StringBuffer) cache.get("foo").getValue(); for (int i = 0; i < 5; i++){ System.out.println("----------------------------------"); System.out.println("Starting iteration " + i); StringBuffer fooBuffer = (StringBuffer) cache.get("foo").getValue(); System.out.println("fooBuffer. = " + fooBuffer.toString()); System.out.println("fooOriginalBuffer = " + fooOriginalBuffer.toString()); System.out.println("cache.getSize() = " + cache.getSize()); System.out.println("----------------------------------"); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Interrupted"); } } } public static void main(String[] args) throws Exception { ExampleCacheProvider cacheProvider = new ExampleCacheProvider(); Reader reader = new Reader(cacheProvider); reader.run(); } } Let’s run it with both updatingFactory options. Output of running the Reader with ExampleCacheEntryFactory (-Dcom.blogspot.mikler.java.cache.factory=create) !!!!! Doing refresh !!!!! ++++++creating entry for key = foo ---------------------------------- Starting iteration 0 fooBuffer. = 35foo0 fooOriginalBuffer = 35foo0 cache.getSize() = 1 ---------------------------------- ---------------------------------- Starting iteration 1 fooBuffer. = 35foo0 fooOriginalBuffer = 35foo0 cache.getSize() = 1 ---------------------------------- !!!!! Doing refresh !!!!! ++++++creating entry for key = foo ---------------------------------- Starting iteration 2 fooBuffer. = 36foo0 fooOriginalBuffer = 35foo0 cache.getSize() = 1 ---------------------------------- ---------------------------------- Starting iteration 3 fooBuffer. = 36foo0 fooOriginalBuffer = 35foo0 cache.getSize() = 1 ---------------------------------- !!!!! Doing refresh !!!!! ++++++creating entry for key = foo ---------------------------------- Starting iteration 4 fooBuffer. = 51foo0 fooOriginalBuffer = 35foo0 cache.getSize() = 1 ---------------------------------- And here how the output looks like while running Reader with ExampleUpdatingCacheEntryFactory as updatingFactory (-Dcom.blogspot.mikler.java.cache.factory=update) !!!!! Doing refresh !!!!! ++++++creating entry for key = foo ---------------------------------- Starting iteration 0 fooBuffer. = 19foo0 fooOriginalBuffer = 19foo0 cache.getSize() = 1 ---------------------------------- ---------------------------------- Starting iteration 1 fooBuffer. = 19foo0 fooOriginalBuffer = 19foo0 cache.getSize() = 1 ---------------------------------- !!!!! Doing refresh !!!!! ~~~~~~UPDATING entry for key = foo ---------------------------------- Starting iteration 2 fooBuffer. = 19foo06 fooOriginalBuffer = 19foo06 cache.getSize() = 1 ---------------------------------- ---------------------------------- Starting iteration 3 fooBuffer. = 19foo06 fooOriginalBuffer = 19foo06 cache.getSize() = 1 ---------------------------------- !!!!! Doing refresh !!!!! ~~~~~~UPDATING entry for key = foo ---------------------------------- Starting iteration 4 fooBuffer. = 19foo067 fooOriginalBuffer = 19foo067 cache.getSize() = 1 ---------------------------------- Conclusion As you can see the output is quite different and here are some conclusions we come to from analyzing it: No NullPointerException is occurs while trying to get object from cache that is not there. It is being created in both cases. If updatingFactory is instance of CacheEntryFactory (ExampleCacheEntryFactory in our case) when cache.refresh() is called each object in cache is being recreated. Also when updatingFactory is instance of CacheEntryFactory final fooOriginalBuffer variable is not updated. Meanwhile in case when updatingFactory is instance of CacheEntryFactory (UpdatingCacheEntryFactory in our case) when cache.refresh() is called each object in cache gets updated instead of being recreated. And final fooOriginalBuffer variable value is updated as well. (Actually this variable itself is passed to updateEntryValue() method of ExampleUpdatingCacheEntryFactory) Instructions about how to check out the source code for this article you can find in the original post. Originally posted on miklerjava.blogspot.com
August 17, 2009
by Mikhail Kolesnik
· 29,857 Views
article thumbnail
Modularity by Example
There are lots of benefits to modularity, some of which I discussed when introducing modularity patterns. But here’s a simple example, which serves as a prelude to some upcoming posts explaining a few of the patterns. In the diagram at right (click to enlarge), the top left quadrant shows a sample system with a relatively complex class structure. When change occurs within a single class, shown in red in the bottom left quadrant, understanding the impact of change is difficult. It appears possible that it can propagate to any class dependent on the class highlighted in red. Assessing the impact of change requires that we analyze the complete class structure. The ripple effect appears significant, and change instills fear. But if the system is modular with classes allocated to these modules, as shown in the bottom right quadrant, then understanding the impact of change can be isolated to a discrete set of modules. And this makes it much easier to identify which modules contain classes that might also change, as shown in the top right quadrant. Change is isolated to classes within modules that are dependent on the module containing the class that is changing. This is a simple example, but it serves as evidence of the need for modular architecture, and illustrates one reason why modularity is so important. Modularity makes understanding the system easier. It makes maintaining the system easier. And it makes reusing system modules much more likely. As systems grow in size and complexity, it’s imperative that we design more modular software. That means we need a module system for the Java platform. It means that module system shouldn’t be shielded from enterprise developers. And it means we need to understand the patterns that are going to provide the guidance necessary in helping us design more modular software. From http://techdistrict.kirkk.com
August 14, 2009
by Kirk Knoernschild
· 16,953 Views
article thumbnail
Simple Python Watchdog Timer
Easily interrupt long portions of code if they take too long to run. #!/usr/bin/python # file: watchdog.py # license: MIT License import signal class Watchdog(Exception): def __init__(self, time=5): self.time = time def __enter__(self): signal.signal(signal.SIGALRM, self.handler) signal.alarm(self.time) def __exit__(self, type, value, traceback): signal.alarm(0) def handler(self, signum, frame): raise self def __str__(self): return "The code you executed took more than %ds to complete" % self.time Example: #!/usr/bin/python # import the class from watchdog import Watchdog # don't allow long_function to take more than 5 seconds to complete try: with Watchdog(5): long_function() except Watchdog: print "long_function() took too long to complete"
August 9, 2009
by Snippets Manager
· 7,079 Views
article thumbnail
EAN13 Check With SQL
SELECT attributes_ean FROM products_attributes WHERE LENGTH(attributes_ean) = 13 AND SUBSTRING((10 - (((( SUBSTRING(attributes_ean FROM 2 FOR 1) + SUBSTRING(attributes_ean FROM 4 FOR 1) + SUBSTRING(attributes_ean FROM 6 FOR 1) + SUBSTRING(attributes_ean FROM 8 FOR 1) + SUBSTRING(attributes_ean FROM 10 FOR 1) + SUBSTRING(attributes_ean FROM 12 FOR 1) )*3) + ( SUBSTRING(attributes_ean FROM 1 FOR 1) + SUBSTRING(attributes_ean FROM 3 FOR 1) + SUBSTRING(attributes_ean FROM 5 FOR 1) + SUBSTRING(attributes_ean FROM 7 FOR 1) + SUBSTRING(attributes_ean FROM 9 FOR 1) + SUBSTRING(attributes_ean FROM 11 FOR 1) )) MOD 10)) FROM -1 FOR 1) != SUBSTRING(attributes_ean FROM 13 FOR 1)
August 5, 2009
by Snippets Manager
· 1,405 Views
article thumbnail
Don't Break the Optimistic Locking
During Jazoon 2009 I got a few minutes of private attention from Mike Keith to my last article about domain models. That small time was worthy the whole conference for me since Mike pointed the gaps in my text as well as some valuable hints on how to better translate domain models in JPA annotations. From that short conversation, a special sentence remains alive in my memory: don't break the optimistic locking. After a review on my original code I agreed with Mike that I was ignoring the optimistic locking in my service layer - a common mistake noticed over the Internet and also in conversation with other friends. The problem is not new and the solution is neither new, but I decided to blog it shortly to my personal reference and eventually for your help. The problem: breaking the optimistic locking. When exposing domain models through web-services you should serialize your entities between the client and the service, and every time you do that you have a detached JPA entity. In order to persist the detached objects in the database you need to re-attach them in to a new persistence context - and that's where the problem begins. Concurrent threads can access the same write method, reading a same entity, modifying it and then writing back the detached entity in the database. In my original code I was reading the latest version of the entity and then copying the field values from the external entity to the latest one. In this way I guaranteed the unbreakable writing code but I felt in the most basic mistake of JPA: I broken the consistency of the entities. From the Mike book: it is just an accident waiting to happen. Below you find the trap example from my original code: @Override public FpUser update(FpUser entity) throws Exception { FpUser attached = manager.find(FpUser.class, entity.getId()); // Here I am modifying the latest entity and not the detached one. attached.setEmail(entity.getEmail()); attached.setName(entity.getName()); return manager.merge(attached); } From the code above, we can enumerate the steps required to bypass the optimistic locking: Client A reads entity.v1 Client B reads entity.v1 Client A modifies the entity.version1 and starts an update.transaction#1 Client B modifies the entity.version1 and starts an update.transaction#2 update.transaction#1 updates the fields received from Client A, merge the entity - that receives the version v2 - but get suspended before to finish. update.transaction#2 updates the fields and received from Client B, updates the version to v3 and finishes returning the entity.v3 to the Client B. update.transaction#1 finishes returning the entity.v2 to the Client A. At the end of the above execution, we have the following scenario: Client A has an instance of the entity version 2 Client B has an instance of the entity version 3 (it actually jumped directly from version 1 to 3, without even noticing the changes of the version 2) The database has the data from version 3 The worse side effect of this trap is that Client A believes the current data persisted in the database is the ones from version 2, but actually it is wrong since the version 3 is currently stored in the database. The inconsistency could be easily detected by the optimistic locking of JPA, but since I am reading the latest version on every update operation the code won't throw the proper exception and the clients will become inconsistent with the server side. Solution: keep it simple The default mechanism specified in JPA to avoid inconsistencies is a Version field applicable to the entities through the @Version annotation. Once you included the version field in your entities, you can just invoke the merge operation to re-attach detached objects and the container will handle the versioning for you - simple and easy (and safe). The above code can be rewritten in a sound manner: @Override public FpUser update(FpUser entity) throws Exception { return manager.merge(entity); } And that's it, fewer lines of code with a more sound and more robust code. I will fix the code in the footprint repository, so the article readers will find a better code in the repository - and perhaps the java.net staff help me to include an addendum to my article warning the readers about that. At least we both know about that from now on :) Other interesting blogs about similar problems: Some J2EE Performance Tips - from Carol McDonald's Retrying transactions in Java - from Panagiotis Astithas TopLink JPA - from Oracle EclipseLink JPA - it replaces the TopLink in JavaEE 6 Before to release your eyes to a next blogger, let me ask you the intrigant question: What if I care only partially about my Entity locking? It is subject for another blog entry, but during my talk with Mike he confessed the next JPA 2.0 includes this feature: the ability to lock partially an entity. In this way, I don't need to throw an exception in a transaction that will affect minor priority fields (the idea behind the common trap I demonstrated above). People that implement a code to avoid exceptions during updates are actually preventing the client to receive exceptions, resolving manually the locking problems. This suicidal trick seems to make sense where some fields support data overwriting - usually an optional or very low priority data. As soon I got a good example I return to this point, now you are free to give me your feedback or to find something else to have fun on the web. My vacations are over :) time to update my working environment and nothing better than a short blog to warm up my brain to the third quarter of Java in 2009. Next step: to conclude the second part of the article, reviewing the gaps and offering a good quality material of Java EE 5 - the last step before to start my complete migration to Java EE 6. From http://weblogs.java.net/blog/felipegaucho
August 4, 2009
by Felipe Gaúcho
· 27,922 Views
article thumbnail
JPA 2.0 Concurrency and Locking
Optimistic locking lets concurrent transactions process simultaneously, but detects and prevent collisions, this works best for applications where most concurrent transactions do not conflict. JPA Optimistic locking allows anyone to read and update an entity, however a version check is made upon commit and an exception is thrown if the version was updated in the database since the entity was read. In JPA for Optimistic locking you annotate an attribute with @Version as shown below: public class Employee { @ID int id; @Version int version; The Version attribute will be incremented with a successful commit. The Version attribute can be an int, short, long, or timestamp. This results in SQL like the following: “UPDATE Employee SET ..., version = version + 1 WHERE id = ? AND version = readVersion” The advantages of optimistic locking are that no database locks are held which can give better scalability. The disadvantages are that the user or application must refresh and retry failed updates. Optimistic Locking Example In the optimistic locking example below, 2 concurrent transactions are updating employee e1. The transaction on the left commits first causing the e1 version attribute to be incremented with the update. The transaction on the right throws an OptimisticLockException because the e1 version attribute is higher than when e1 was read, causing the transaction to roll back. Additional Locking with JPA Entity Locking APIs With JPA it is possible to lock an entity, this allows you to control when, where and which kind of locking to use. JPA 1.0 only supported Optimistic read or Optimistic write locking. JPA 2.0 supports Optimistic and Pessimistic locking, this is layered on top of @Version checking described above. JPA 2.0 LockMode values : OPTIMISTIC (JPA 1.0 READ): perform a version check on locked Entity before commit, throw an OptimisticLockException if Entity version mismatch. OPTIMISTIC_FORCE_INCREMENT (JPA 1.0 WRITE) perform a version check on locked Entity before commit, throw an OptimisticLockException if Entity version mismatch, force an increment to the version at the end of the transaction, even if the entity is not modified. PESSIMISTIC: lock the database row when reading PESSIMISTIC_FORCE_INCREMENT lock the database row when reading, force an increment to the version at the end of the transaction, even if the entity is not modified. There are multiple APIs to specify locking an Entity: EntityManager methods: lock, find, refresh Query methods: setLockMode NamedQuery annotation: lockMode element OPTIMISTIC (READ) LockMode Example In the optimistic locking example below, transaction1 on the left updates the department name for dep , which causes dep's version attribute to be incremented. Transaction2 on the right gives an employee a raise if he's in the "Eng" department. Version checking on the employee attribute would not throw an exception in this example since it was the dep Version attribute that was updated in transaction1. In this example the employee change should not commit if the department was changed after reading, so an OPTIMISTIC lock is used : em.lock(dep, OPTIMISTIC). This will cause a version check on the dep Entity before committing transaction2 which will throw an OptimisticLockException because the dep version attribute is higher than when dep was read, causing the transaction to roll back. OPTIMISTIC_FORCE_INCREMENT (write) LockMode Example In the OPTIMISTIC_FORCE_INCREMENT locking example below, transaction2 on the right wants to be sure that the dep name does not change during the transaction, so transaction2 locks the dep Entity em.lock(dep, OPTIMISTIC_FORCE_INCREMENT) and then calls em.flush() which causes dep's version attribute to be incremented in the database. This will cause any parallel updates to dep to throw an OptimisticLockException and roll back. In transaction1 on the left at commit time when the dep version attribute is checked and found to be stale, an OptimisticLockException is thrown Pessimistic Concurrency Pessimistic concurrency locks the database row when data is read, this is the equivalent of a (SELECT . . . FOR UPDATE [NOWAIT]) . Pessimistic locking ensures that transactions do not update the same entity at the same time, which can simplify application code, but it limits concurrent access to the data which can cause bad scalability and may cause deadlocks. Pessimistic locking is better for applications with a higher risk of contention among concurrent transactions. The examples below show: reading an entity and then locking it later reading an entity with a lock reading an entity, then later refreshing it with a lock The Trade-offs are the longer you hold the lock the greater the risks of bad scalability and deadlocks. The later you lock the greater the risk of stale data, which can then cause an optimistic lock exception, if the entity was updated after reading but before locking. The right locking approach depends on your application: what is the risk of risk of contention among concurrent transactions? What are the requirements for scalability? What are the requirements for user re-trying on failure? For More Information: Preventing Non-Repeatable Reads in JPA Using EclipseLink Java Persistence API 2.0: What's New ? What's New and Exciting in JPA 2.0 Beginning Java™ EE 6 Platform with GlassFish™ 3 Pro EJB 3: Java Persistence API (JPA 1.0)
August 3, 2009
by Carol McDonald
· 51,534 Views · 1 Like
article thumbnail
One Big DAO, or One DAO Per Table/Object?
For a long time I have been doing DAO's in my applications.I have usually used the model of having one DAO per type persisted, or per database table. You know, a PersonDao, a CarDao, a BlablaDao etc. Today, as I was writing an application in which I am too lazy to use a DAO layer (because most of the persistence operations are 1-liners), I was thinking: Should I add that DAO layer, or should I not care? Well, of course I should add the DAO layer, so SQL statements etc. can be reused, and modified in a central place, if the database schema changes. Shame on me for being lazy. But here is my question to you all: Do you also use one DAO per type persisted? Or, do you create one BIG DAO which contains all DAO logic? I am asking, because I feel tempted to go with just one BIG DAO though I have no experiences with that. Like I said, I usually use one DAO per type persisted. But a BIIIG DAO seems compelling to me... Here are the immediate benefits I can see: It definately makes it easier to find all DAO methods in a project. It makes it very easy to share connections and transactions between different DAO calls. You don't get confused about whether readCarsForPerson() belongs in the CarDao or PersonDao (I would probably say CarDao since it returns Car's). By using one big DAO the DAO becomes an abstraction of the total database / datastore, rather than an abstraction of each table / type etc. What is your opinion on this? One big DAO, or one per type? Does anyone have any experiences?
July 30, 2009
by Jakob Jenkov
· 47,066 Views · 3 Likes
article thumbnail
Autocomplete Combobox In Java With Filtering And Inserting New Text
import java.awt.EventQueue; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractListModel; import javax.swing.ComboBoxModel; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.Timer; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.JTextComponent; import javax.swing.text.PlainDocument; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; /** * Autocomplete combobox with filtering and * text inserting of new text * @author Exterminator13 */ public class AutoCompleteCombo extends JComboBox{ private static final Logger logger = Logger.getLogger(AutoCompleteCombo.class); private Model model = new Model(); private final JTextComponent textComponent = (JTextComponent) getEditor().getEditorComponent(); private boolean modelFilling = false; private boolean updatePopup; public AutoCompleteCombo() { setEditable(true); logger.debug("setPattern() called from constructor"); setPattern(null); updatePopup = false; textComponent.setDocument(new AutoCompleteDocument()); setModel(model); setSelectedItem(null); new Timer(20, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (updatePopup && isDisplayable()) { setPopupVisible(false); if (model.getSize() > 0) { setPopupVisible(true); } updatePopup = false; } } }).start(); } private class AutoCompleteDocument extends PlainDocument { boolean arrowKeyPressed = false; public AutoCompleteDocument() { textComponent.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_ENTER) { logger.debug("[key listener] enter key pressed"); //there is no such element in the model for now String text = textComponent.getText(); if (!model.data.contains(text)) { logger.debug("addToTop() called from keyPressed()"); addToTop(text); } } else if (key == KeyEvent.VK_UP || key == KeyEvent.VK_DOWN) { arrowKeyPressed = true; logger.debug("arrow key pressed"); } } }); } void updateModel() throws BadLocationException { String textToMatch = getText(0, getLength()); logger.debug("setPattern() called from updateModel()"); setPattern(textToMatch); } @Override public void remove(int offs, int len) throws BadLocationException { if (modelFilling) { logger.debug("[remove] model is being filled now"); return; } super.remove(offs, len); if (arrowKeyPressed) { arrowKeyPressed = false; logger.debug("[remove] arrow key was pressed, updateModel() was NOT called"); } else { logger.debug("[remove] calling updateModel()"); updateModel(); } clearSelection(); } @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (modelFilling) { logger.debug("[insert] model is being filled now"); return; } // insert the string into the document super.insertString(offs, str, a); // if (enterKeyPressed) { // logger.debug("[insertString] enter key was pressed"); // enterKeyPressed = false; // return; // } String text = getText(0, getLength()); if (arrowKeyPressed) { logger.debug("[insert] arrow key was pressed, updateModel() was NOT called"); model.setSelectedItem(text); logger.debug( String.format("[insert] model.setSelectedItem(%s)", text) ); arrowKeyPressed = false; } else if(!text.equals(getSelectedItem())){ logger.debug("[insert] calling updateModel()"); updateModel(); } clearSelection(); } } public void setText(String text) { if (model.data.contains(text)) { setSelectedItem(text); } else { addToTop(text); setSelectedIndex(0); } } public String getText() { return getEditor().getItem().toString(); } private String previousPattern = null; private void setPattern(String pattern) { if(pattern!=null && pattern.trim().isEmpty()) pattern = null; if(previousPattern==null && pattern ==null || pattern!=null && pattern.equals(previousPattern)) { logger.debug("[setPatter] pattern is the same as previous: "+previousPattern); return; } previousPattern = pattern; modelFilling = true; // logger.debug("setPattern(): start"); model.setPattern(pattern); if(logger.isDebugEnabled()) { StringBuilder b = new StringBuilder(100); b.append("pattern filter '").append(pattern==null ? "null" : pattern).append("' set:\n"); for(int i=0; i list = new ArrayList(limit); private List lowercase = new ArrayList(limit); private List filtered; void add(String s) { list.add(s); lowercase.add(s.toLowerCase()); } void addToTop(String s) { list.add(0, s); lowercase.add(0, s.toLowerCase()); } void remove(int index) { list.remove(index); lowercase.remove(index); } List getList() { return list; } List getFiltered() { if(filtered==null) filtered = list; return filtered; } int size() { return list.size(); } void setPattern(String pattern) { if (pattern == null || pattern.isEmpty()) { filtered = list; AutoCompleteCombo.this.setSelectedItem(model.getElementAt(0)); logger.debug( String.format("[setPattern] combo.setSelectedItem(null)") ); } else { filtered = new ArrayList(limit); pattern = pattern.toLowerCase(); for(int i=0; isize2) { fireIntervalRemoved(this, size2, size1-1); fireContentsChanged(this, 0, size2-1); } } public void addToTop(String aString) { if(aString==null || data.contains(aString)) return; if(data.size()==0) data.add(aString); else data.addToTop(aString); while(data.size()>limit) { int index = data.size()-1; data.remove(index); } setPattern(null); model.setSelectedItem(aString); logger.debug( String.format("[addToTop] model.setSelectedItem(%s)", aString) ); //saving into options if (data.size() > 0) { writeData(); } } @Override public Object getSelectedItem() { return selected; } @Override public void setSelectedItem(Object anObject) { if ((selected != null && !selected.equals(anObject)) || selected == null && anObject != null) { selected = (String) anObject; fireContentsChanged(this, -1, -1); } } @Override public int getSize() { return data.getFiltered().size(); } @Override public Object getElementAt(int index) { return data.getFiltered().get(index); } } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { // Logger root = Logger.getRootLogger(); // root.addAppender(new ConsoleAppender(new PatternLayout("%d{ISO8601} [%5p] %m at %l%n"))); Logger root = Logger.getRootLogger(); root.addAppender(new ConsoleAppender(new PatternLayout("%d{ISO8601} %m at %L%n"))); // BasicConfigurator.configure(); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new GridLayout(3, 1)); final JLabel label = new JLabel("label "); frame.add(label); final AutoCompleteCombo combo = new AutoCompleteCombo(); // combo.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() { // // @Override // public void keyReleased(KeyEvent e) { // if (e.getKeyCode() == KeyEvent.VK_ENTER) { // String text = combo.getEditor().getItem().toString(); // if(text.isEmpty()) // return; // combo.addToTop(text); // } // } // }); frame.add(combo); JComboBox combo2 = new JComboBox(new String[] {"Item 1", "Item 2", "Item 3", "Item 4"}); combo2.setEditable(true); frame.add(combo2); frame.pack(); frame.setSize( 500, frame.getHeight() ); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } }
July 25, 2009
by Snippets Manager
· 19,459 Views
article thumbnail
Android vs iPhone Development: A Comparison
A few months ago I ventured into the world of Mobile development and created an application (Hudson Helper) for both iPhone and Android. This article is about my experiences, comparing Android and iPhone development with a focus on tools, platform and the developer experience. Before going much further I should note that my comparison is with considerable bias. I’ve spent the past 12+ years in Java development, having spent much of my career building developer tools. Since January of 2004 I’ve been building plug-ins for Eclipse, and before that plug-ins for NetBeans. This bias is somewhat tempered with several years of C and C++ development. With this background I find that I’m very critical of developer tools. Developer productivity is key — anything that takes away from the flow of a developer in the zone is a real problem. Language, Programming Model and Platform Language The language of choice for iPhone development is Objective-C. Objective-C is a language based on C with extensions for object-oriented concepts, such as classes, inheritance, interfaces, messages, dynamic typing, etc. The Java language is used when developing for Android (though it doesn’t actually get compiled to bytecode). Java is a no-brainer. I have to say that it’s nice not to have to learn a new language to target mobile. Existing skillsets don’t come easy — so reuse of expertise is worth a lot. It took a little while to wrap my head around some of the language features available with Objective-C. I soon discovered that I really loved certain language features, such as message passing (instead of calling methods), categories and named arguments. I did find however that the syntax of Objective-C is cumbersome. I’m still not used to ‘+’ and ‘-’ for static and member methods, too many parentheses are required, and in general I just felt like I had to type way to much to express a simple concept. The IDE didn’t help much with this either (more on that later). One thing that really became clear to me is that Objective-C, though it may have been visionary for its time, is really a language of the '80s. Certain issues such as split header and implementation files and violation of DRY are really time-wasters, and not small ones at that. I found myself constantly switching back and forth between files, which not only has a cost in navigation (which file to open?) but with every file opened your sense of context must be recreated (where’s the caret, what’s selected, where am I in the file, how is this file organized). As far as DRY, must I really do 5 things to declare a property?? (declare in the class definition, again to declare getter/settter, initialize in the init method, @synthesize in the implementation, release in dealloc). Here’s what I mean: Server.h @interface Server : Updatable {NSString *name; <-- declare the property }@property (nonatomic,retain) NSString *name; <--- declare the property again Server.m @synthesize name; <-- implement getter/setter-(void) dealloc {[name release]; <-- release memory} If you ask me, everything in Server.m should go away. Another gotcha here is the positional relevance of @synthesize. Java has a similar problem with properties, though not quite so bad — and the IDE helps you write your getter/setter. Pointers in Objective-C, though powerful, are also another time-waster. This is where Java really shines with its garbage collection. I found that I was constantly considering whether allocated objects were freed appropriately. Code flow is poor since application logic is littered with memory management. I only have so many brain cycles available — why do I have to think about this other cruft that’s not really a core concern of the application domain? Of course this gets even worse when trying to figure out where things went wrong if you make a mistake. Zombies help, but still don’t make it obvious if you’ve accessed something that was deallocated. Other issues include deallocating something twice, autoreleasing something twice. I also found it non-intuitive when to retain return values from methods. Another annoyance of Objective-C is the patterns that must be followed: implementing correct init and dealloc methods is non-trivial. @synthesized getters and setters for properties with retain should not be called in these methods. So many conventions and rules to remember! Though I understand why there’s a separation of alloc and init, it’s still overly wordy to specify [[aloc Foo] initWithArg: arg]. Why not just [new Foo arg]? Or how about new Foo(arg) -- oh, wait, that’s just like Java! Objective-C’s imports and forward-declarations (@class) are a pain. Though these issues exist with Java development, Eclipse’s JDT is so good that I’ve almost forgotten what it’s like to write an import. All you have to do is Ctrl+Space to auto-complete a class name or Ctrl+Shift+O to organize imports and voila! Of course Java is not perfect either, however this fact is hidden from me due to the fact that I’ve been living in Java for a very long time. Sometimes I wish that Java were more Groovy-like, however I’m used to it and the tooling is so good. Platform On Android I found that I could readily use the Java runtime classes. Some, but not all, of the standard Java RT classes are available on Android. I didn’t find this a problem, since most of the standard Java IO, network and regex libraries are available. Android RT classes appear to be based on Harmony, which has been around long enough to be stable. With iPhone on the other hand, finding the functionality that I needed was painful. Classes and methods are poorly organized. When to look for a static method versus a class with members was not clear to me. Also depending on the framework used, naming conventions and code organization would differ. I suppose this is the legacy of an older platform. Areas where functionality was lacking that I found painful were regular expressions, string handling and XML parsing. I ended up using the excellent Regex Kit Lite for regular expressions. For XML parsing I implemented a parser abstraction over libxml, only to discover later that I may have had an easier time with NSXMLParser which is a lot more like SAX. On the iPhone when things didn’t work as expected I had to resort to Google and hope that others had encountered the same problem. This technique was hampered by Apple’s earlier NDA policy, which meant that iPhone content is pretty thin on the net. In some cases I would resort to guesswork and experimentation to find a solution. Android has the benefit of being open source. Within minutes I had the full Android platform source code on my system, and had re-built the SDK from sources to ensure that the source I had matched the runtime classes in the emulator. So not only could I see how things were implemented in the Android platform and learn by example, I could step through the platform code in the emulator and discover why my code wasn’t producing the desired results. In general I found the layout, organization, and naming conventions of Android platform classes was consistent and predictable. This made it much easier to learn. Programming Model The iPhone platform does a great job of encouraging an MVC design pattern. With this design pattern built in to the platform, building the UI was simple and I didn’t have to figure out how to organize the UI component design myself. It also means that when looking at sample code, it’s all organized in the same way. Android also does a good job with design patterns, though their concepts varied significantly from the iPhone. With Android’s support for multiple processes and component reuse, the platform itself provides support for Intents and Activities (an Intent is just a variant of a command). The design results in a better user experience, however it does introduce some complexity for the developer: when starting one Activity from another, an Intent is used to communicate any parameters. These parameters cannot be passed by reference — only by value. Where on the iPhone it’s simple to have screens sharing the same data structures, on Android this requires some forethought. Apparently Android applications can manage the back button and have everything occur inside a single Activity, however this is not the norm. Both Android and iPhone provide a way of declaring user preferences in XML. Both platforms provide a default UI for editing those preferences, which is great. Android’s XML format is extensible allowing custom UI components to be integrated, which makes user preferences a breeze. iPhone developers that wish to customize preferences will have to implement a UI from scratch, which is a lot more work. Testing and Continuous Integration I’m of the opinion that every development effort should include unit tests. Teams of size greater than one should also include Continuous Integration. Android developers will be happy to know that they can write JUnit tests. I could even launch these from the Eclipse UI after some classpath fiddling. Though I didn’t try it, I assume that it’s trivial to run these from Ant and your favorite CI server such as Hudson. I did see some iPhone unit test documentation with the iPhone SDK but didn’t take the time to explore it — so I can’t comment there. Resources Apple does an excellent job of providing lots of resources for developers. Important concepts are explained in videos, which makes grasping concepts easy — however I did find that videos progressed slowly and I was watching for what seemed like hours to find information that should have taken minutes. Luckily Apple also provides lots of sample applications and code to demonstrate API usage. Android developers also have access to loads of resources. The guide and API reference are installed with the SDK, so everything is available when offline (which for me is important since I do a lot of my work in transit). I found the Android development resources better organized and spent less time looking and more time finding. In particular the ApiDemos sample app provides a great starting point. I also downloaded many open source Android projects for ideas on architecture and API usage. This is an area where Android has the advantage, with Apple’s previous NDA policy there isn’t much out there in terms of open source for iPhone. Tooling For me tooling was a real shocker. These are the categories of tooling that I’ll cover: IDE, UI builder, debugger, profiler. Almost everything else is related to provisioning, and in that area I didn’t notice much in the way of differences between Android and iPhone. IDE Android development leverages the excellent JDT tools, which are pretty much stock and standard with every Eclipse installation. I’ve used these tools now for many years and they’re excellent. Everything Java is indexed, the IDE has a rich model of the source code, and refactoring is so seamless that it has changed the way that I work. Perhaps the best feature of JDT is its incremental compiler, which provides immediate feedback with errors and warnings as you type. This eliminates the code-compile-wait-for-feedback cycle that was so common in the '80s and '90s. Errors and warnings are updated in the Java editor as I type, giving me instant feedback. I didn’t realize just how valuable this feature is until I was coding Objective-C in XCode — when I became acutely aware at how waiting for compiler feedback can break the flow of programming. Other key features that make Eclipse so amazing to work with are: content assist quick-fixes organize imports open type (CTRL+Shift+T) refactorings Integrated javadoc and content assist is quite possibly the best way to learn an unfamiliar API. In Ecipse not only are all classes and methods immediately available in the context in which you’re writing code, their documentation is presented alongside. Content Assist with Integrated Javadoc XCode is so shockingly bad that I almost don’t know where to start. Here’s a minimum list of things that I think need fixing in order for XCode to become a viable IDE: Content assist that actually works. Content assist provided by XCode is often wrong, and almost always suggests a small subset of what’s actually available. A decent window/editor management system. XCode and it’s associated tools (debugger) like to open lots of windows. Want to open a file? How about a new window for you! Very quickly I found myself in open-window-hell. The operating system’s window management is designed for managing multiple applications, not multiple editors within an IDE. It’s simply not capable of providing management of editors in an environment as sophisticated as an IDE. A project tree view that sorts files alphabetically. Really! Integrated API documentation. I found that I was constantly switching out of the IDE and searching for API documentation using Appkido. This may seem trivial, but it really breaks the flow. One area of Eclipse that simply can’t be matched is Mylyn. Integrated task management and a focused interface introduce huge efficiencies into any project, small or large. If you haven’t yet tried out Mylyn, it’s definitely worth your time to take a look. A good place to start is Mylyn’s Getting Started page. UI Builder iPhone app developers are given a pretty good UI builder. It does a great job of showing the UI as it will actually appear. It’s flexible and can model some pretty sophisticated UIs, so I was impressed. I found that using it was a little tricky — I had to read the documentation two or three times before I could really figure out how to use it properly. The Android UI builder I found pretty useless: it can’t display UIs how they’ll actually appear, and it’s UI is way too inefficient. I found that I coded all of the UIs directly in the XML source view of the UI builder. There the content assist and validation were pretty good, making it the easiest way for me to build a UI. Debugger Having used to the Java debugger in Eclipse I was shocked at the state of the debugger in XCode. With Eclipse I can see and modify variable values. Not so in XCode. Maybe this is simply the state of affairs when debugging native code, but it sure affects the usefulness of the debugger. XCode often seemed confused as to the type of an object and presented me with a pointer value and no detail. This is a sharp contrast to Eclipse, where I can drill down through an object graph with ease. I found the XCode debugger UI extremely difficult to use. Clicking on the stack to show code in an editor caused new windows to open, eventually resulting in dozens of windows open. In addition I found that watch expressions rarely worked for me. Profiler and Heap Analysis An area where Apple development tools excel is in profiling and heap analysis. These tools seemed mature and easy to use. With no prior experience with these specific tools I was able to gain a better understanding of my app within minutes, find and fix several memory leaks and improve performance. XCode Memory Leak Detection Android developers must use Android’s traceview application, which I found worked well but required significantly more effort to configure and operate. I was surprised to find that the source code must be changed in order to get the trace files required for analysis. I’m not sure if Android can provide heap dumps in hprof format. If it can then the awesome MAT tool could be used to analyze heap usage. According to this article Android can produce hprof heap data, though I haven’t tried it. App Store It goes without saying that the iPhone app store is excellent in that you can sell into many countries worldwide with a single setup. I was able to provide my Canadian bank account number, sign a few legal agreements and I was up and running. Getting an app into the store however is frustrating to say the least. Apple must approve every app before it is accepted into the store. Mine got rejected multiple times. Each time it was rejected I was given almost no information about why. When I emailed them to clarify the problem, I received what looked like a canned response indicating that I should refer to previous correspondence. If it weren’t so frustrating I would have found it funny. I highly recommend reading Brian Stormont’s Avoiding iPhone App Rejection from Apple and Dan Grigsby’s Part 2 follow-up. Of course once I started selling Hudson Helper I realized that Apple won’t send me any money unless the payout is greater than $250. This is true not only of the first payout, but every payout. Google market on the other hand requires a minimum of $1 for each payout. Both the iPhone app store and Google market take about %30 of your app selling price. $0.99 applications have to have high volume, or they’re simply not worth your time. The Google market by comparison to the Apple app store is terrible in that you can only sell into a handful of countries. You also can’t see or install apps that cost money on a developer phone. Actually you can, but not if the app has copy protection — which is almost every non-free app. On the other hand when you upload your app to the app store it’s available within minutes, so you don’t have to worry about an approval process. To set up a merchant account with Google market, I had to provide a US address and bank account number, since Google doesn’t support Canada. For me this was a pain, but not too bad since I live within a few kilometers of the US border. I rode my bike down to the US and opened an account with Horizon bank. The bank required a passport and driver’s license, so no problem there. Why Google doesn’t support more countries I don’t know. At the very least Google market should accept alternate payment methods for countries that are not supported by Google checkout. Summary Android’s platform and developer tools are excellent. Leveraging Java and the Eclipse IDE are major winning factors for Android. Apple’s developer tools are shockingly bad by comparison. The Objective-C language and platform APIs are cumbersome and poorly organized. Overall when developing for the iPhone I felt like I was back in 1993. These factors combined in my estimation make application development about three times more expensive when developing for iPhone. The only area where Apple’s developer tools excelled was in profiling and heap analysis. Apple’s app store from a user’s standpoint and from a worldwide coverage standpoint are excellent. In this area Google market for Android is weak. Development for iPhone may improve as tools such as iphonical (MDD for iPhone) and objectiveclipse (Eclipse plug-in for Objective-C) emerge. We may see a shake-up in the mobile market, with at least 18 new Android handsets being released this year. Until that happens, iPhone will remain a market leader and developers will have to put up with XCode and Objective-C. For me, my love is with Android. Sure, the iPhone is great — but can you install a new Linux kernel? From http://greensopinion.blogspot.com/
July 6, 2009
by David Green
· 93,288 Views
article thumbnail
Continuations to Continue
Jetty-6 Continuations introduced the concept of asynchronous servlets to provide scalability and quality of service to web 2.0 applications such as chat, collaborative editing, price publishing, as well as powering HTTP based frameworks like cometd, apache camel, openfire XMPP and flex BlazeDS. With the introduction of similar asynchronous features in Servlet-3.0, some have suggested that the Continuation API would be deprecated. Instead, the Continuation API has been updated to provide a simplified portability run asynchronously on any servlet 3.0 container as well as on Jetty (6,7 & 8). Continuations will work synchronously (blocking) on any 2.5 servlet container. Thus programming to the Continuations API allows your application to achieve asynchronicity today without waiting for the release of stable 3.0 containers (and needing to upgrade all your associated infrastructure). Continuation Improvements The old continuation API threw an exception when the continuation was suspended, so that the thread to exit the service method of the servlet/filter. This caused a potential race condition as a continuation would need to be registered with the asynchronous service before the suspend, so that service could do a resume before the actual suspend, unless a common mutex was used. Also, the old continuation API had a waiting continuation that would work on non-jetty servers. However the behaviour of this the waiting continuation was a little different to the normal continuation, so code had to be carefully written to work for both. The new continuation API does not throw an exception from suspend, so the continuation can be suspended before it is registered with any services and the mutex is no longer needed. With the use of a ContinuationFilter for non asynchronous containers, the continuation will now behaive identically in all servers. Continuations and Servlet 3.0 The servlet 3.0 asynchronous API introduced some additional asynchronous features not supported by jetty 6 continuations, including: The ability to complete an asynchronous request without dispatching Support for wrapped requests and responses. Listeners for asynchronous events Dispatching asynchronous requests to specific contexts and/or resources While powerful, these additional features may also be very complicated and confusing. Thus the new Continuation API has cherry picked the good ideas and represents a good compromise between power and complexity. The servlet 3.0 features adopted are: The completing a continuation without resuming. Support for response wrappers. Optional listeners for asynchronous events. Using The Continuation API The new continuation API is available in Jetty-7 and is not expected to significantly change in future releases. Also the continuation library is intended to be deployed in WEB-INF/lib and is portable. Thus the jetty-7 continuation jar will work asynchronously when deployed in jetty-6, jetty-7, jetty-8 or any servlet 3.0 container. Obtaining a Continuation The ContinuationSupport factory class can be used to obtain a continuation instance associated with a request: Continuation continuation = ContinuationSupport.getContinuation(request); Suspending a Request The suspend a request, the suspend method is called on the continuation: void doGet(HttpServletRequest request, HttpServletResponse response) { ... continuation.suspend(); ... } After this method has been called, the lifecycle of the request will be extended beyond the return to the container from the Servlet.service(...) method and Filter.doFilter(...) calls. After these dispatch methods return to, as suspended request will not be committed and a response will not be sent to the HTTP client. Once a request is suspended, the continuation should be registered with an asynchronous service so that it may be used by an asynchronous callback once the waited for event happens. The request will be suspended until either continuation.resume() or continuation.complete() is called. If neither is called then the continuation will timeout after a default period or a time set before the suspend by a call to continuation.setTimeout(long). If no timeout listeners resume or complete the continuation, then the continuation is resumed with continuation.isExpired() true. There is a variation of suspend for use with request wrappers and the complete lifecycle (see below): continuation.suspend(response); Suspension is analogous to the servlet 3.0 request.startAsync() method. Unlike jetty-6 continuations, an exception is not thrown by suspend and the method should return normally. This allows the registration of the continuation to occur after suspension and avoids the need for a mutex. If an exception is desirable (to bypass code that is unaware of continuations and may try to commit the response), then continuation.undispatch() may be called to exit the current thread from the current dispatch by throwing a ContinuationThrowable. Resuming a Request Once an asynchronous event has occurred, the continuation can be resumed: void myAsyncCallback(Object results) { continuation.setAttribute("results",results); continuation.resume(); } Once a continuation is resumed, the request is redispatched to the servlet container, almost as if the request had been received again. However during the redispatch, the continuation.isInitial() method returns false and any attributes set by the asynchronous handler are available. Continuation resume is analogous to Servlet 3.0 AsyncContext.dispatch(). Completing Request As an alternative to completing a request, an asynchronous handler may write the response itself. After writing the response, the handler must indicate the request handling is complete by calling the complete method: void myAsyncCallback(Object results) { writeResults(continuation.getServletResponse(),results); continuation.complete(); } After complete is called, the container schedules the response to be committed and flushed. Continuation resume is analogous to Servlet 3.0 AsyncContext.complete(). Continuation Listeners An application may monitor the status of a continuation by using a ContinuationListener: void doGet(HttpServletRequest request, HttpServletResponse response) { ... Continuation continuation = ContinuationSupport.getContinuation(request); continuation.addContinuationListener(new ContinuationListener() { public void onTimeout(Continuation continuation) { ... } public void onComplete(Continuation continuation) { ... } }); continuation.suspend(); ... } Continuation listeners are analogous to Servlet 3.0 AsyncListeners. Continuation Patterns Suspend Resume Pattern The suspend/resume style is used when a servlet and/or filter is used to generate the response after a asynchronous wait that is terminated by an asynchronous handler. Typically a request attribute is used to pass results and to indicate if the request has already been suspended. void doGet(HttpServletRequest request, HttpServletResponse response) { // if we need to get asynchronous results Object results = request.getAttribute("results); if (results==null) { final Continuation continuation = ContinuationSupport.getContinuation(request); // if this is not a timeout if (continuation.isExpired()) { sendMyTimeoutResponse(response); return; } // suspend the request continuation.suspend(); // always suspend before registration // register with async service. The code here will depend on the // the service used (see Jetty HttpClient for example) myAsyncHandler.register(new MyHandler() { public void onMyEvent(Object result) { continuation.setAttribute("results",results); continuation.resume(); } }); return; // or continuation.undispatch(); } // Send the results sendMyResultResponse(response,results); } This style is very good when the response needs the facilities of the servlet container (eg it uses a web framework) or if the one event may resume many requests so the containers thread pool can be used to handle each of them. Suspend Continue Pattern The suspend/complete style is used when an asynchronous handler is used to generate the response: void doGet(HttpServletRequest request, HttpServletResponse response) { final Continuation continuation = ContinuationSupport.getContinuation(request); // if this is not a timeout if (continuation.isExpired()) { sendMyTimeoutResponse(request,response); return; } // suspend the request continuation.suspend(response); // response may be wrapped. // register with async service. The code here will depend on the // the service used (see Jetty HttpClient for example) myAsyncHandler.register(new MyHandler() { public void onMyEvent(Object result) { sendMyResultResponse(continuation.getServletResponse(),results); continuation.complete(); } }); } This style is very good when the response does not needs the facilities of the servlet container (eg it does not use a web framework) and if an event will resume only one continuation. If many responses are to be sent (eg a chat room), then writing one response may block and cause a DOS on the other responses. Continuation Examples Chat Servlet The ChatServlet example shows how the suspend/resume style can be used to directly code a chat room. The same principles are applied to frameworks like cometd.org which provide an richer environment for such applications, based on Continuations. Quality of Service Filter The QoSFilter(javadoc), uses suspend/resume style to limit the number of requests simultaneously within the filter. This can be used to protect a JDBC connection pool or other limited resource from too many simultaneous requests. If too many requests are received, the extra requests wait for a short time on a semaphore, before being suspended. As requests within the filter return, they use a priority queue to resume the suspended requests. This allows your authenticated or priority users to get a better share of your servers resources when the machine is under load. Denial of Service Filter The DosFilter(javadoc) is similar to the QoSFilter, but protects a web application from a denial of service attack (as best you can from within a web application). If too many requests are detected coming from one source, then those requests are suspended and a warning generated. This works on the assumption that the attacker may be written in simple blocking style, so by suspending you are hopefully consuming their resources. True protection from DOS can only be achieved by network devices (or eugenics :). Proxy Servlet The ProxyServlet uses the suspend/complete style and the jetty asynchronous client to implement a scalable Proxy server (or transparent proxy). Gzip Filter The jetty GzipFilter is a filter that implements dynamic compression by wrapping the response objects. This filter has been enhanced to understand continuations, so that if a request is suspended in suspend/complete style and the wrapped response is passed to the asynchronous handler, then a ContinuationListener is used to finish the wrapped response. This allows the GzipFilter to work with the asynchronous ProxyServlet and to compress the proxied responses. Where do you get it? You can read about it, or download it with jetty or include it in your maven project like this pom.xml From http://blogs.webtide.com
July 2, 2009
by Greg Wilkins
· 12,562 Views
article thumbnail
Three Forms of RESTEasy Client
RESTEasy comes in three forms of client APIs: JAX-RS annotated Interface proxying Lower level fluid HTTP API ClientRequestFactory - generates #1 and #2, and has a get template method The ClientRequestFactory encapsulates RESTEasy client's most interest feature: client interceptors. Those interceptors come in three flavors: ClientExecutionInterceptor - intercept "execution" of a request. You can do things like client-side caching, performance montoring and request modifications with this interceptor. MessageBodyReaderInterceptor - intercepts the conversion process from raw bites to object MessageBodyWriteInterceptor - intercepts the conversion process from object to raw bites I'm going to use the Flickr "REST" API To demonstrate the three forms of client and the interceptor framework. All (or at least most) of the code found in this blog can be downloaded (zip) from the RESTEasy SVN repo. Arjen Poutsma wrote up a great blog post on how to use the API with Spring's RestTemplate a while back. That post can give you lots of detail on how the Flickr API works. I'm going to re-write that same example using RESTEasy's framework. In my example, I'm going to have two types of calls to the Flickr API: Search for photos - "http://www.flickr.com/services/rest?method=flickr.photos.search&;api+key={api-key}&tags={tag}&per_page=8" Retrieve photos - "http://static.flickr.com/{server}/{id}_{secret}_m.jpg" XML to Java Object The search for photos returns an XML response that looks a bit like this: All I really care about is the server, the id and the secret so that I can retrieve the photos. In RESTEasy, the easiest way to translates XML is to use JAXB. Here's how my FlickrResponse object maps to the XML above: @XmlRootElement(name = "rsp") public class FlickrResponse { @XmlElementWrapper(name = "photos") @XmlElement(name="photo") public List photos; } class Photo { @XmlAttribute public String server, id, secret, title, owner; public String getPublicURL() { return UriBuilder.fromUri("http://www.flickr.com/photos/").path( "/{owner}/{id}").build(owner, id).toString(); } } In ideal REST API, I wouldn't have to construct the photo URL myself, but with Flickr I had to do it. As you can see, it's not that painful to construct. Reading a photo. Now that I have my XML reader in place, I want to create a .jpg to ImageIcon converter. I'm going to be showing photos on a Swing application, and Swing needs an ImageIcon object. JAX-RS has a slick abstraction machanism to convert raw data into any object you'd like: MessageBodyReader and MessageBodyWriter. Since I only care about reading an image, I'm going to implement a MessageBodyReader. RESTEasy reuqires all readers and writers to be annotated with JAX-RS's @Provider annotation which tells JAX-RS systems that this is an infrastructure object. My reader has to read in a byte array and convert it to an ImageIcon. RESTEasy has a utility method to do the byte reading and ImageIcon has a constructor that takes a byte array, so my work is pretty simple: @Provider @Produces("*/*") public class ImageIconMessageBodyReader implements MessageBodyReader { public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type.isAssignableFrom(ImageIcon.class); } public ImageIcon readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { return new ImageIcon(ReadFromStream.readFromStream(1024 * 4, entityStream)); } } I wish that there was a more succinct API (perhaps using annotations) for creating this method, but for now you have to create a boat-load of method parameters to do some really straight forward work. Perhaps that can be tackled in JAX-RS 2.0 Performance Logging with RESTEasy The next thing I'm going to tackle is a performance monitor using RESTEasy's ClientExecutionInterceptor and MessageBodyReaderInterceptor. I care about how long the execution took and how long it takes to transform a byte array into either MXL or an ImageIcon. public class LoggingExecutionInterceptor implements ClientExecutionInterceptor, MessageBodyReaderInterceptor { private final static Logger logger = LoggerFactory .getLogger(LoggingExecutionInterceptor.class); @SuppressWarnings("unchecked") public ClientResponse execute(ClientExecutionContext ctx) throws Exception { long start = System.currentTimeMillis(); ClientResponse response = ctx.proceed(); String contentLength = (String) response.getMetadata().getFirst( HttpHeaderNames.CONTENT_LENGTH); logger.info(String.format("Read url %s in %d ms size %s.", ctx.getRequest().getUri(), System.currentTimeMillis() - start, contentLength)); return response; } public Object read(MessageBodyReaderContext ctx) throws IOException, WebApplicationException { long start = System.currentTimeMillis(); Object result = ctx.proceed(); logger.info(String.format("Read mediaType %s as %s in %d ms.", ctx.getMediaType().toString(), ctx.getType().getName(), System.currentTimeMillis() - start)); return result; } } I hope that this code is clear enough to get a sense of how the RESTEasy API works. RESTEasy setup RESTEasy requires just a bit of default set up. I also need to tell RESTEasy about the ImageIconMessageBodyReader and LoggingExecutionInterceptor. private static ClientRequestFactory initializeRequests() { ResteasyProviderFactory instance = ResteasyProviderFactory.getInstance(); RegisterBuiltin.register(instance); instance.registerProvider(ImageIconMessageBodyReader.class); ClientRequestFactory clientRequestFactory = new ClientRequestFactory(); clientRequestFactory.getPrefixInterceptors().registerInterceptor(new LoggingExecutionInterceptor()); return clientRequestFactory; } Everything here should be relatively straight forward, except for getPrefixInterceptors(). Here's what's happening: RESTEasy registers all default @Provider classses specified in META-INF/services/javax.ws.rs.ext.Providers - including String converters and and JAXB converters Explicitely register the ImageIconMessageBodyReader Create a new ClientRequestFactory register my LoggingExecutionInterceptor so that any future client.get(..) calls, client.createProxy, or client.createRequest will use that interceptor Searching for photos I'm going to show you the three RESTEasy client types that can be used to search for photos: We're going to use a static variable to encapsulate our URLs: public static final String photoSearchUrl = "http://www.flickr.com/services/rest?method=flickr.photos.search&per_page=8&sort=interestingness-desc&api+key={api-key}&{type}={searchTerm}"; Note: you can apply for your own Flickr API Key. Let's with the newfangled ClientRequestFactory to search for photos: FlickrResponse photos = clientRequestFactory.get(photoSearchUrl, FlickrResponse.class, apiKey, type, searchTerm); That's all there really is to it. That uses the photoSearch URI template, gets a FlickrResponse, and fills in the template with the last three parameters. Getting a photo I'll demonstrate the "JAX-RS annotated Interface proxying" by showing how to retrieve a photo. Let's start with an interface: public interface PhotoResource { @GET @Path("/{server}/{id}_{secret}_m.jpg") ImageIcon read(@PathParam("server") String server, @PathParam("id") String id, @PathParam("secret") String secret); } This tells RESTEasy that we'll be performing a GET, the URI template is a "/{server}/{id}_{secret}_m.jpg" and that method parameters will be used to populate the URI template's variables. Here's an example of how this interface is used: // set the "base URI" clientRequestFactory.setBase(new URI("http://static.flickr.com")) ... PhotoResource photoResource = clientRequestFactory.createProxy(PhotoResource.class); for (final Photo photo : photos.photos) { photo.image = executor.submit(new Callable() { public ImageIcon call() throws Exception { ImageIcon ic = photoResource.read(photo.server, photo.id, photo.secret); ... } }); } This code iterates over the photos from FlickrResponse and retrieves an ImageIcon based on the parameters passed into the proxied method. "JAX-RS annotated Interface proxying" also allow you to perform POSTs/PUTs/DELETEs, set HTTP headers, set Cookies, set form parameters and even supply a URL. It can be used when you want to have a remove "service" interface and have complicated HTTP communication requirements. For the sake of completeness, here's an example of using ClientRequest for those same calls: ImageIcon ic = client.createRequest(photoUrlTemplate) .pathParameters(photo.server, photo.id, photo.secret) .get().getEntity(ImageIcon.class) As you can see, ClientRequest does something similar in nature to the other two approaches, but is a bit more verbose. ClientRequests allows you to perform GET/POST/DELETE/PUT; set headers, query parameters, cookies form parameters and of course uri template parameters. Full Flickr Application Let's put those prevous calls into a fully functional application. I'm going to use the ClientRequestFactory.get() method for both XML and ImageIcons: public class SimpleFlickrClient { public static final String photoSearchUrl = "http://www.flickr.com/services/rest?method=flickr.photos.search&per_page=8&sort=interestingness-desc&api+key={api-key}&{type}={searchTerm}"; public static final String photoUrlTemplate = "http://static.flickr.com/{server}/{id}_{secret}_m.jpg" public static void main(String args[]) throws Exception { final String searchTerm = "dolphin"; ClientRequestFactory client = initializeRequests(); // apply for api key at - http://www.flickr.com/services/api/keys/apply FlickrResponse photos = client.get(photoSearchUrl, FlickrResponse.class, args[0], "text", searchTerm); JFrame frame = new JFrame(searchTerm + " photos"); frame.setLayout(new GridLayout(2, photos.photos.size() / 2)); for (Photo photo : photos.photos) { JLabel image = new JLabel(client.get(photoUrlTemplate, ImageIcon.class, photo.server, photo.id, photo.secret)); image.setBorder(BorderFactory.createTitledBorder(photo.title)); frame.add(image); } frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } private static ClientRequestFactory initializeRequests() { ResteasyProviderFactory instance = ResteasyProviderFactory .getInstance(); RegisterBuiltin.register(instance); instance.registerProvider(ImageIconMessageBodyReader.class); ClientRequestFactory client = new ClientRequestFactory(); client.getPrefixInterceptors().registerInterceptor( new LoggingExecutionInterceptor()); return client; } } Running this code (the fully mavenized application is downloadable) will produces the following image: and a standard out logging that looks something like: 125 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://www.flickr.com/services/rest?method=flickr.photos.search&per_page=8&sort=interestingness-desc&api+key=0c20edc102588ab938587bc286132b6e&text=dolphin 437 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://www.flickr.com/services/rest?method=flickr.photos.search&per_page=8&sort=interestingness-desc&api+key=0c20edc102588ab938587bc286132b6e&text=dolphin in 312 ms size 1410. 703 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType text/xml;charset="utf-8" as org.jboss.resteasy.examples.flickr.FlickrResponse in 250 ms. 796 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/3546/3344501816_7849e5b9d1_m.jpg 1265 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/3546/3344501816_7849e5b9d1_m.jpg in 469 ms size 22271. 1781 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 516 ms. 1797 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/3640/3280270877_625d72bd9f_m.jpg 2265 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/3640/3280270877_625d72bd9f_m.jpg in 468 ms size 54941. 3031 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 766 ms. 3031 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/3269/2987261000_a66b646be5_m.jpg 3453 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/3269/2987261000_a66b646be5_m.jpg in 422 ms size 25750. 3937 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 484 ms. 3937 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/2296/2004396589_2222cf91bb_m.jpg 4390 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/2296/2004396589_2222cf91bb_m.jpg in 453 ms size 31783. 5000 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 610 ms. 5000 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/2322/1752011018_bef30f1360_m.jpg 5422 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/2322/1752011018_bef30f1360_m.jpg in 422 ms size 28925. 6015 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 593 ms. 6015 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/1104/542661469_d1a21eb9bd_m.jpg 6484 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/1104/542661469_d1a21eb9bd_m.jpg in 469 ms size 5961. 6625 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 141 ms. 6625 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/49/142731041_4e9eff1694_m.jpg 7094 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/49/142731041_4e9eff1694_m.jpg in 469 ms size 16020. 7484 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 390 ms. 7484 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Reading url http://static.flickr.com/45/142730518_79013350b8_m.jpg 7953 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read url http://static.flickr.com/45/142730518_79013350b8_m.jpg in 469 ms size 20054. 8359 [main] INFO org.jboss.resteasy.examples.resteasy.LoggingExecutionInterceptor - Read mediaType image/jpeg as javax.swing.ImageIcon in 406 ms. Client Approach Comparison The JAX-RS proxy approach is declarative, and the ClientRequest approach is imparative. The ClientRequest code is a bit more concise overall than it's proxied counterpart, but has the disadvantage of form and function, which the proxy separates the two. The ClientRequestFactory.get() method is simple and limited, but will likely cover 80%+ of cases. The overall use of ClientRequestFactory's ClientRequest and proxy creation methods will likely become invaluable as you add more interceptors. LightweightBrowserCache The CachingInterceptor is one of the most compelling existing REST interceptors. It performs fully RESTful client-side caching, similar to what you're browser would do. It uses HTTP caching headers as instructions of what should be cached and for how long. The Flickr client, unfortunately, can't really take advantage of it because the RESTEasy client implementation caches in memory, and the code executes the requests for XML and images happens only once per JVM. However, the RESTEasy caching solution is pluggable. You can add coherence to your classpath, and modify the initializeRequests like so: private static ClientRequestFactory initializeRequests() { ResteasyProviderFactory instance = ResteasyProviderFactory .getInstance(); RegisterBuiltin.register(instance); instance.registerProvider(ImageIconMessageBodyReader.class); ClientRequestFactory client = new ClientRequestFactory(); client.getPrefixInterceptors().registerInterceptor( new LoggingExecutionInterceptor()); client.getPrefixInterceptors().registerInterceptor(new CacheInterceptor( new LightweightBrowserCache(new MapCache(CacheFactory.getCache("flickr"))))); return client; } CacheFactory.getCache("flickr") returns an instance of a Coherence "Enterprise HashMap" which performs complex system-wide caching without much configuration. Everything else is RESTEasy To see this in action, all you'll have to do is: Start up one instance of this application. Wait until all of the images are loaded. Start up another instance of this application. The first instance will take a bit longer to start up than before, since Coherence has to initialize; the caching time is practically 0. The second instance should run dramatically quicker because of the caching. Conclusion I hope you've gotten enough of a taste of the three client flavors that RESTEasy provides. I also hope that you "GET" the picture of how RESTEasy's client interceptors work. If you have any questions and suggestions about it, please let me know by commenting here, emailing me or twittering me!
July 1, 2009
by Solomon Duskis
· 56,339 Views
article thumbnail
JMS Over HTTP Using OpenMQ (Sun Java System Message Queue and HTTP Tunneling)
You may have already faced a situation where you need to have messaging capabilities in your application while your client application runs in an environment, which you have no control over its network configuration and restrictions. Such situation lead to the fact that you can not use JMS communication over designated ports like 7676 and so. You may simply put JMS away and follow another protocol or even plain HTTP communication to address your architecture and design requirement, but we can not easily put pure JMS API capabilities away as we may need durable subscription over a proven and already well tested and established design and architecture. Different JMS implementation providers provide different type capabilities to address such a requirement. ActiveMQ provide HTTP and HTTPS transport for JMS API and described it here. OpenMQ provide different transport protocol and access channels to access OpenMQ functionalities from different prgramming . One of the access channles which involve HTTP is named Universal Message Service (UMS) which provide a simple REST interaction template to place messages and comsume them from any programming language and device which can interact with a network server. UMS has some limitations which is simply understandable based on the RESTful nature of UMS. For current version of OpenMQ, it only supports Message Queues as destinations so there is no publish-subscribe functionality available. Another capability which involve HTTP is JMS over HTTP or simply JMS HTTP tunneling. OpenMQ JMS implementation supports HTTP/s as transport protocol if we configure the message broker properly. Well I said the JMS implementation support HTTP/S as a transport protocol which means we as user of the JMS API see almost no difference in the way that we use the JMS API. We can use publish-subscribe, point to point, durable subscription, transaction and whatever provided in the JMS API. First, lets overview the OpenMQ installation and configuration then we will take a look at an example to see what changes between using JMS API and JMS API over HTTP transport. Installation process is as follow: OpenMQ project provides a Java EE web application which interact with OpenMQ broker from one side and Sun JMS implementation on the other side. Interaction of this application with the client and MQ broker is highly customizable in different aspects like Broker port number, client poll inrval, Broker address and so on. Download OpenMQ from https://mq.dev.java.net/ it should be a zip which is different for each platform. Install the MQ by unzipping the above file and running ./installer or installer.bat or so. After the installation completed, go to install_folder/var/mq/instances/imqbroker/props and open the config.properties in a text editor like notepad or emeditor or gedit. Add the following line to the end of the above file: imq.service.activelist=jms,admin,httpjms Now goto install_folder/mq/lib/ and pick the imqhttp.war file. deploy the file into your Servlet container or application server (I went with GlassFish). After you deployed the file start the application server or Servlet container Now it is time to start the MQ broker: launch a terminal or cmd console and goto install_folder/mq/bin now execute ./imqbrokerd -port 7979 (it maybe like imqbrokerd.bat -port 7979 for Windows ) This command will start the MQ broker and keep it listening on port 7979 for incoming connection To test the overall operations: Open a browser and tray to surf http://127.0.0.1:8080/imqhttp/tunnel or whatever URL which points to the newly deployed application . If you saw "HTTP tunneling Servlet ready." as the first line in the response page then we are ready for last step. Now let's see how we can publish some messages, this sample code assume that we have configured the message broker and assumes that we have the following two JAR files in the classpath. These JAR files are available in install_folder/mq/lib/ imq.jar jms.jar Now the Publisher code: public class Publisher { public void publish(String messageContent) { try { String addressList = "http://127.0.0.1:8080/imqhttp/tunnel"; com.sun.messaging.TopicConnectionFactory topicConnectionFactory = new com.sun.messaging.TopicConnectionFactory(); topicConnectionFactory.setProperty(com.sun.messaging.ConnectionConfiguration.imqAddressList, addressList); javax.jms.Topic top; javax.jms.Connection con = topicConnectionFactory.createTopicConnection("admin", "admin"); javax.jms.Session session = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); top = session.createTopic("DIRECT_TOPIC"); MessageProducer prod = session.createProducer(top); Message textMessage = session.createTextMessage(messageContent); prod.send(textMessage); prod.close(); session.close(); con.close(); } catch (JMSException ex) { ex.printStackTrace(); } } public static void main(String args[]) { Publisher p = new Publisher(); for (int i = 1; i < 10; i++) { p.publish("Sample Text Message Content: " + i); } } } As you can see the only difference is the connection URL which uses http instead of mq and point to a Servlet container address instead of pointing to the Broker listening address. The subscriber sample code follow a similar pattern. Here I write a sample durable subscriber so you can see that we can use durable subscribtion over HTTP. But you should note that HTTP transport uses polling and continuesly open communication channel which can introduce some overload on the server. class SimpleListener implements MessageListener { public void onMessage(Message msg) { System.out.println("On Message Called"); if (msg instanceof TextMessage) { try { System.out.print(((TextMessage) msg).getText()); } catch (JMSException ex) { ex.printStackTrace(); } } } } public class Subscriber { /** * @param args the command line arguments */ public void subscribe(String clientID, String susbscritpionID) { try { // TODO code application logic here String addressList = "http://127.0.0.1:8080/imqhttp/tunnel"; com.sun.messaging.TopicConnectionFactory topicConnectionFactory = new com.sun.messaging.TopicConnectionFactory(); topicConnectionFactory.setProperty(com.sun.messaging.ConnectionConfiguration.imqAddressList, addressList); javax.jms.Topic top; javax.jms.Connection con = topicConnectionFactory.createTopicConnection("admin", "admin"); con.setClientID(clientID); javax.jms.Session session = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); top = session.createTopic("DIRECT_TOPIC"); TopicSubscriber topicSubscriber = session.createDurableSubscriber(top, susbscritpionID); topicSubscriber.setMessageListener(new SimpleListener()); con.start(); } catch (JMSException ex) { ex.printStackTrace(); } } public static void main(String args[]) { Subscriber sub = new Subscriber(); sub.subscribe("C19", "C1_011"); } } Now how you can test the entire example and monitor the MQ? it is very simple by utilizing the provided tools. Do the following steps to test the overall durable subscription system: Run a subscriber Run another subscriber with a different client ID Run a publisher once or twice Kill the second subscriber Run a publisher once Run the subscriber and you can see that the subscriber will fetch all messages which arrived after it shut down-ed. Note that we can not have two separate client with same client ID running because the broker will not be able to distinguish which client it should send the messages. You can monitor the queue and the broker using: ./imqadmin which can be found in install_folder/mq/bin this software shows how many durable subscribers are around and how many messages are pending for each subscriber and so on. You can monitor the Queue in real-time mode using the following command which can be executed in install_folder/mq/bin ./imqcmd -b 127.0.0.1:7979 metrics dst -t t -n DIRECT_TOPIC The command will ask for username and password, give admin/admin for it The sample code for this entry can be found Here. The sample code is a NetBeans project with the publisher and the subscriber source code. A complete documentation of OpenMQ is available at its documentation centre. You can see how you can change different port numbers or configure different properties of the Broker and HTTP tunneling web application communication.
June 22, 2009
by Masoud Kalali
· 34,826 Views
  • Previous
  • ...
  • 1610
  • 1611
  • 1612
  • 1613
  • 1614
  • 1615
  • 1616
  • 1617
  • 1618
  • 1619
  • ...
  • 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
×