Tuesday, December 22, 2009
Intertech Trained? Get a $10 Starbucks Gift Card
With over 10,000 developers trained since 1991, technology professionals recognize the value of Intertech training. The Intertech Trained logo provides the recognition you need to excel in your career and validates of your training and skills.
To get the Intertech Trained logo and information about how to display it on your pages, contact Tony Caswell at tcaswell@intertch.com.
Sunday, December 6, 2009
JSF Component Power Demonstrated through Data Table
When it comes to MVC Web frameworks in Java there are a lot of choices. The leading frameworks or "Big 3" as they are sometimes know are usually considered to be Struts, Spring MVC and JavaServer Faces (JSF). Each framework has its pros/cons, its supporters and detractors. For those looking to some for a good comprehensive comparison, you might want to check out Matt Raible's blog and presentation here.
JSF is an extremely powerful, component driven framework. In fact, its nickname is "Swing for the Web." The JSF data table serves as an excellent example of JSF's Swing-like capability. A JSF data table can display a collection of data objects while also offering features such as pagination, column header/footers, style sheet application (for header, even and odd rows, etc.).
Data Table Example
First, to familiarize you with the JSF data table, let's look at a small example. In a JSP, use the <h:dataTable…> JSF tag to define a table in your page. The <h:column …> tag helps to define the table columns while the <f:facet …> tag is used to define header and footer rows.
<f:view>
<h:dataTable value="#{orderBean.orderModel}" var="order"
binding="#{orderBean.orderTable}" headerClass="columnHeader"
rowClasses="oddRow,evenRow">
<h:column>
<f:facet name="header">
<h:outputText value="Description" />
</f:facet>
<h:outputText value="#{order.description}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Customer" />
</f:facet>
<h:outputText value="#{order.customer}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Price" />
</f:facet>
<h:outputText value="#{order.price}">
<f:convertNumber type="currency" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Quantity" />
</f:facet>
<h:outputText value="#{order.quantity}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Cost" />
</f:facet>
<h:outputText value="#{order.cost}">
<f:convertNumber type="currency" />
</h:outputText>
</h:column>
<h:column>
<h:form>
<h:commandLink action="#{orderBean.editOrder}">Edit</h:commandLink>
<f:verbatim>
</f:verbatim>
<h:commandLink action="#{orderBean.deleteOrder}">Delete</h:commandLink>
<f:verbatim>
</f:verbatim>
<h:commandLink action="#{orderBean.displayOrder}">
<f:param name="id" value="#{order.id}" />Display</h:commandLink>
</h:form>
</h:column>
</h:dataTable>
</f:view>
In this example a collection of Order objects is obtained from a JSF managed bean (OrderManagedBean) to populate the data table. Note the value attribute to the <h:dataTable…> element above. Unified expression language is used to bind the orderModel property of an instance of a managed bean to the data table.
The var attribute on the data table establishes the name of the variable used to reference to each object in the nested elements of the data table. In this example, the name "order" is used to reference each of the Order objects in the collection provided to the data table.
Unified expression language in the <h:column …> element allows properties of the Order objects to be obtained and displayed.
Note how cascading styles can be used to differentiate odd and even rows. Other attributes like first, rows, cellspacing, cellpadding, etc. can add pagination and better layout to the table. See the JSF API documentation for a complete list of how to customize the data table.
For completeness of the example, here is the managed bean definition for this example in the JSF faces-config.xml.
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<managed-bean>
<managed-bean-name>orderBean</managed-bean-name>
<managed-bean-class>com.intertech.beans.OrderManageBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
Populating a Data Table
Flexibility epitomizes JSF components. Extreme flexibility can be demonstrated by data table population and row selection. With regard to the binding, the JSF data table can be populated with an array, a List, an SQL ResultSet, a JSTL SQL Result, or even a JSF table data model object as shown here.
public class OrderManageBean {
private ListDataModel orderModel;
private OrderDAO dao = new OrderDAO();
public ListDataModel getOrderModel() {
if (orderModel == null) {
List<Order> list = dao.getOrders();
orderModel = new ListDataModel(list);
}
return orderModel;
}
public void setOrderModel(ListDataModel orderModel) {
this.orderModel = orderModel;
}
…
}
All that is required is that the getOrderModel( ) method must return one of these types of objects.
Selecting and Working With a Row in the Data Table
When displaying a list of objects, a common requirement is to provide a means to select an object, or more precisely an object's row, for the purpose of working with that object – for example to edit or delete the object. Again, JSF provides the flexibility to accomplish this task in many ways.
You can bind a property of the managed bean to the data table component itself. Then, call on the getRowData( ) method of the data table object to get the selected object. Below, the managed bean's edit action method uses the bound data table component to get the selected Order object.
private UIData orderTable;
public UIData getOrderTable() {
return orderTable;
}
public void setOrderTable(UIData orderTable) {
this.orderTable = orderTable;
}
public String editOrder() {
Order o = (Order) orderTable.getRowData();
//do work to get and edit an order
dao.editOrder(o);
return null;
}
You can bind a property of the managed bean to the data table model and call on the getRowData( ) method of the model object to get the selected object. This is the case in the delete method below, which uses the bound data table model to fetch the selected Order object.
public String deleteOrder() {
Order o = (Order) orderModel.getRowData();
//do work to delete order
dao.deleteOrder(o);
return null;
}
Or, you can add the object's unique identifier as a parameter to the link or button in the data table (see the <h:commandLink ….> to Display above) so that when it is pushed, the object's identifier is passed to action method. The id can then be used to fetch the selected object. Here, the managed bean's details method uses the id passed via the command link in the page to fetch the selected Order to display.
public String displayOrder() {
Order o = (Order) orderModel.getRowData();
//do work to get and display an order
dao.getOrder(o);
return null;
}
The code for this example is available here.
Powerful JSF
Again, JSF is a very powerful MVC framework in Java. Its component nature, as represented by the data table, allows it to be customized quickly/easily and allows for great integration into technologies like AJAX. To be fair, JSF has also suffered some performance criticism (see JavaOne presentation here). As JSF 2.0 is now out, more organizations are exploring (or possibly re-exploring) it for Web applications. JSF 2.0 will be part of Java EE 6 which is expected to be released at anytime.
Intrigued by the power and capability of JSF? Come attend Intertech's Complete JSF class.
Wednesday, October 21, 2009
Help!!! What training do you need?
In addition to influencing our next course offerings, let me give you another reason to fill out the survey. If you complete the survey and provide Intertech with your email address at the end of the survey, Intertech will send you a coupon for $250 off your next Intertech class (valid for public classes held in 2010)! Its simple and takes about 10 minutes to complete. Just click on the survey link here - 2010 Intertech Course Planning Survey
Monday, October 19, 2009
Interest in Noop?
Have you heard of Noop yet? Noop (see project page here) is a new programming language developed by Google engineers (although not sponsored directly by Google) that is expected to run on the Java Virtual Machine. Why a new program language? According to the project Web site, the purpose of Noop is "encouraging what we believe to be good coding practices and discouraging the worst offenses."
Fans of Spring and the importance of testing (especially unit testing) will note the first two goals of the new language are to build dependency injection and testability right into the language versus having to use 3rd party libraries to bring DI and testing into application environments. Not included in the language (supposedly to make things clearer, simpler, and easier to maintain), among other things are statics, primitive types, and subclassing (implementation inheritance).
To find out more about Noop join their mailing list at noop@googlegroups.com. Also, a short article on Noop can be found on Application Development Trends website here.
Sunday, October 11, 2009
Hibernate’s Smart Automatic Dirty Check
I am one lucky guy. As an instructor, my job begins anew each week. Each week, I face a new group of people trying to learn a technology or skill. People have asked "don't you get bored teaching." How could I? Each week the topic changes and the needs of my students change. And when I am not teaching, I am working to understand new technologies and how/when to put it into courseware.
But perhaps what makes my job the most enjoyable is when I have a group of students that are really engaging and come up with questions that make me stop and think. In other words, they challenge me to improve my own skills/knowledge on a topic that I think I already know pretty well. This week, I was teaching Hibernate and had just one of those questions from one of my students, Josephine.
We were exploring Hibernate's automatic dirty checking. As those familiar with Hibernate have learned, Hibernate knows persistent objects and tracks state change to those objects. No explicit call to save (or update) a persistent object is necessary. Just committing the transaction causes the new state of a persistent object to be synchronized to the database. However, Josephine asked what would happen if the state of an object was changed and then changed back again to the original state in the same transaction? Would Hibernate know that no real change occurred and therefore avoid an SQL call to the database? What's your guess? In fact, the answer surprised me when I tested it out.
To describe the situation with a little more detail, explore the following persistent class and Hibernate mapping file. Nothing real complex about the Contact class or its mapping to a Contact table.
public class Contact {
private Long id = 0L;
private String firstName;
private String lastName;
private Date dateOfBirth;
private boolean married = false;
private int children;
private int age;
//getters and setters and constructors
}
<hibernate-mapping package="com.intertech.domain">
<class name="Contact">
<id name="id">
<generator class="increment" />
</id>
<property name="firstName" column="first_name" not-null="true" />
<property name="lastName" column="last_name" not-null="true" />
<property name="dateOfBirth" column="date_of_birth" type="date" not-null="true" />
<property name="married" />
<property name="children" />
<property name="age" formula="datediff('yy', date_of_birth, curdate())" access="field"/>
</class>
</hibernate-mapping>
Now check out this little bit of test code. In this example, the Contact with an ID of 2 (2 long) has 4 children.
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
Transaction t = s.beginTransaction();
Contact c = (Contact) s.load(com.intertech.domain.Contact.class, 2L);
c.setChildren(32);
c.setChildren(4);
t.commit();
s.close();
So, what happens if code updates the number of children to another number (in this case 32) and then returning it to 4? Take a look at the log output (with hibernate.show_sql=true). The answer surprised me!
Hibernate:
select
contact0_.id as id0_0_,
contact0_.first_name as first2_0_0_,
contact0_.last_name as last3_0_0_,
contact0_.date_of_birth as date4_0_0_,
contact0_.married as married0_0_,
contact0_.children as children0_0_,
datediff('yy',contact0_.date_of_birth,curdate()) as formula0_0_ from
Contact contact0_
where
contact0_.id=?
The SQL select is made to load to the Contact, but no update SQL is issued. Hibernate actually checks to see if the state has undergone real modification before issuing an SQL to synchronize the state with the database. Another case of the students teaching the instructor.
Come join me in learning Hibernate in Intertech's Complete Hibernate class. We offer both live and virtual training, and while I may not have all the answers, I'll work hard to find them for you! That's one of the best parts of my job!
Sunday, October 4, 2009
HandlerInterceptors in Spring Web MVC Framework
In general, Interceptors, or more precisely HandlerInterceptors, are used to provide cross cutting concerns to a Spring MVC Web application. Here is a quote from Rod Johnson et al's book Java Development with the Spring Framework: "HandlerInterceptors provide the capability to intercept incoming HTTP requests. Interceptors are useful to add additional crosscutting behavior to your web infrastructure, such as security, logging, auditing." Of course, you'll find "crosscutting behavior" the purpose of AOP as well. So indeed, HandlerInterceptors and AOP serve a similar purpose; that is they serve to collect cross cutting concern code usually sprinkled throughout the core concerns of an application. AOP provides a framework for providing cross-cutting concerns throughout all types of applications and application components. HandlerInterceptors are an extension point to a Spring MVC framework, and as such, are a means to provide cross-cutting concerns specific to Web applications. These special cross-cutting concern components also have access to the Web request, response and ModelAndView objects; something normal AOP aspects are not provided directly without some work. If you are unfamiliar with AOP, the Spring API documentation also indicates that HandlerInterceptors work like Servlet Filters.
While there is a rather large amount of documentation and tutorials on intertwining AOP into a Spring application, there is not as much on HandlerInterceptors. So let me use this blog entry to show you how HandlerInterceptors work both in Spring 2 and in Spring 2.5 where annotations (rather than XML) are used to specify the controller and request mapping.
HandlerInterceptors must implement the org.springframework.web.servlet.HandlerInterceptor interface. This interface defines three methods (preHandle, postHandle, and afterCompletion) that get called before a handler is executed (#1 in the diagram below), after a handler is executed but before the view is rendered (#2 below), and after completely handling a Web request and rendering the view(#3 below). These methods allow for all sorts of pre and post processing in the chain of execution associated to each and every Web request.
Here is a simple implementation of the HandlerInterceptor.
package com.intertech.controllers;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.HandlerInterceptor;
public class
TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("In pre-processing/n");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("done with request/n");
}
@Override
public void postHandle(HttpServletRequest request, HtpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("In post-processing/n");
}
}
Note that the preHandle method returns a boolean. If false is returned, the interceptor indicates the normal execution chain should be aborted. The result is to send an HTTP error or other custom response to the user. The postHandle method is provided a copy of the ModelAndView object. This allows the interceptor to modify the model information or view displayed as normally determined by the Spring MVC controller. Finally, the afterCompletion method serves as a kind of callback after processing the request and rendering the view. This method can and should clean up any resources used by the interceptor.In Spring 2, interceptors are woven into the Web request execution chain through XML configuration of the handler mapping (note the interceptors property for the SimpleUrlHandlerMapping example below).
<bean id="testInterceptor" class="com.intertech.controllers.TestInterceptor" />
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="testInterceptor"/>
</list>
</property>
<property name="mappings">
<props>
<prop key="/addcontact.request">addContactController
</prop>
<prop key="/displayContacts.request">manageContactsController
</prop>
<prop key="/deleteContact.request">manageContactsController
</prop>
</props>
</property>
</bean>
In Spring 2.5 and better, since handler mapping is handled via @RequestMapping annotations, the interceptor must be added to the DefaultAnnotationHandlerMapping. In Spring 2.5 and beyond, the DispatcherServlet enables the DefaultAnnotationHandlerMapping by default, which looks for @RequestMapping annotations on @Controllers. However, the DefaultAnnotationHandlerMapping can still be added to the Spring configuration file and the interceptors added to this handler mapping as shown below.
<bean id="testInterceptor" class="com.intertech.controllers.TestInterceptor" />
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list><ref bean="testInterceptor"/></list>
</property>
</bean>
Spring already comes with several interceptor adapters (HandlerInterceptorAdapter, LocaleChangeInterceptor, ThemeChangeInterceptor, UserRoleAuthorizationInterceptor, WebContentInterceptor, WebRequestHandlerInterceptorAdapter) so that developers don't have to implement common Web application cross cutting concerns. For example, the UserRoleAuthorizationInterceptor checks the authorization of the current user against the Java EE security roles, as evaluated by HttpServletRequest's isUserInRole method.To learn more about the Spring Framework or Spring Web MVC, please consider joining me for Intertech's Complete Spring Core or Complete Spring Web class. We offer training at our facility as well as virtually right to your desktop wherever you are.
Wednesday, September 2, 2009
Oracle-Sun Acquisition Near Approval
Thursday, August 27, 2009
Simplifying the Hibernate Inverse Attribute on Associations
Hibernate is a framework to make storing and retrieving persistent objects and their association to one another simpler. While this is generally true, there are aspects of Hibernate configuration and mapping that can be challenging to learn and understand. Perhaps, one of the toughest to teach people is that of the inverse setting on a bi-directional relationship mapping in a one-to-many or many-to-many association. Without an understanding of the objects, the association, and SQL needed to save them, people new to Hibernate often struggle with this setting.
In fact, the inverse attribute on an association mapping can be easily understood with a simple example. So to start, assume there are two entities: BallPlayer and Team. As anyone who has played team sports knows, a team has many players, but a player can be on only one team at anytime. Therefore, the relationship between BallPlayer and Team is a one-to-many relationship, and in this example it is bi-directional. That is, a BallPlayer knows the team he plays for, and the Team knows the players on it. The UML showing the BallPlayer and Team attributes and the ERD diagrams for Player and Team are shown below.
The Hibernate mapping files for both BallPlayer and Team are straightforward.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.intertech.domain">
<class name="BallPlayer" table="Player" abstract="true">
<id name="id" access="field">
<generator class="sequence">
<param name="sequence">common_seq</param>
</generator>
</id>
<property name="name" />
<property name="dob" column="date_of_birth" />
<property name="uniformNumber" column="uniform_number" />
<many-to-one name="team" column="team_id" cascade="all"
class="com.intertech.domain.Team" not-null="true" />
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.intertech.domain">
<class name="Team">
<id name="id" access="field">
<generator class="sequence">
<param name="sequence">common_seq</param>
</generator>
</id>
<property name="nickname" />
<property name="founded" />
<set name="players" inverse="true" cascade="all">
<key column="team_id" />
<one-to-many class="com.intertech.domain.BallPlayer" />
</set>
</class>
</hibernate-mapping>
Note the inverse="true" on the <set> element in the Team mapping. When used, the inverse attribute must be set on the collection (in this case the <set> on Team) side of the association rather than the side containing the <many-to-one> element (the BallPlayer in this case). In a many-to-many relationship, the inverse attribute can be placed on the collection element on either side.
OK, but what is this inverse attribute all about? Well, to understand it, examine some test code that exercises the BallPlayer to Team relationship.
Calendar dob = Calendar.getInstance();
dob.set(1942, Calendar.DECEMBER, 13);
BallPlayer fergie = new BallPlayer();
fergie.setName("Ferguson Jenkins");
fergie.setDob(dob);
fergie.setUniformNumber((short) 31);
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Team cubs = (Team) session.get(Team.class, 1L);
cubs.addPlayer(fergie);
fergie.setTeam(cubs);
transaction.commit();
session.close();
In this Hibernate code, a new BallPlayer (fergie) is created and associated to an already persistent Team (cubs) object. Once the BallPlayer and Team are associated to one another and since Team is already persistent, cascading persistence causes the BallPlayer (fergie) and relationship to the Team (cubs) to be saved.
The SQL issued to the database (shown with show_sql and use_sql_comments all set to true in the Hibernate configuration) when the test code above executes is shown below.
Hibernate: /* load com.intertech.domain.Team */ select team0_.id as id1_0_, team0_.nickname as nickname1_0_, team0_.founded as founded1_0_ from Team team0_ where team0_.id=?
Hibernate: /* load one-to-many com.intertech.domain.Team.players */ select players0_.team_id as team5_1_, players0_.id as id1_, players0_.id as id0_0_, players0_.name as name0_0_, players0_.date_of_birth as date3_0_0_, players0_.uniform_number as uniform4_0_0_, players0_.team_id as team5_0_0_ from Player players0_ where players0_.team_id=?
Hibernate: call next value for common_seq
Hibernate: /* insert com.intertech.domain.BallPlayer */ insert into Player (name, date_of_birth, uniform_number, team_id, id) values (?, ?, ?, ?, ?)
However, when the inverse="true" is removed from the Team mapping file, look how the SQL changes.
Hibernate: /* load com.intertech.domain.Team */ select team0_.id as id1_0_, team0_.nickname as nickname1_0_, team0_.founded as founded1_0_ from Team team0_ where team0_.id=?
Hibernate: call next value for common_seq
Hibernate: /* insert com.intertech.domain.BallPlayer */ insert into Player (name, date_of_birth, uniform_number, team_id, id) values (?, ?, ?, ?, ?)
Hibernate: /* create one-to-many row com.intertech.domain.Team.players */ update Player set team_id=? where id=?
It might be hard to see at first, but one extra SQL statement got executed. Notice the extra SQL update statement that is called (the last line in italics)? What gives? Why the extra SQL? This is a result of the absences of the inverse attribute on the relationship mapping.
From a database perspective, since only the Player table holds the reference (foreign key) to the Team, only one insert is needed for the relationship to be persisted – an insert into the Player table. However, Hibernate does not detect this fact by default. In the persistence context, all Hibernate knows is that both persistent objects (the BallPlayer called fergie and the Team called cubs) have been created or modified and need to be persisted. Therefore, at the next point of synchronization (transaction commit in this case) with the database, Hibernate attempts to persist both. If inverse attribute is not set to true, Hibernate looks at Team and notices the new BallPlayer.
It inserts the new BallPlayer, and association from cubs-to-fergie. However, it then looks at the new BallPlayer and sees the relationship fergie-to-cubs. Not told that the relationship is the inverse of one it has already taken care of, it thinks an update might be necessary to save this new relationship. Thus the extra "update Player set team_id=? where id=?" SQL is issued.
So, the inverse=true attribute informs Hibernate of the existence of a bidirectional relationship which allows it to ignore the relationship from the Team to BallPlayer direction.
This raises an important issue in your management of Java objects and their association to each other. With inverse="true", Hibernate essentially ignores the association of Team to BallPlayer. Therefore, if you add a BallPlayer to Team, but do not handle the reverse association in your coding, the association is ignored!
// - forget to do this - aPlayer.setTeam(aTeam);
aTeam.addPlayer(aPlayer);
session.save(aTeam);
session.save(aPlayer);
Hibernate manages the persistence of Java objects and their associations to each other into the database, but only if they are physically there! For this reason, good Hibernate developers write methods to update both sides of an entity relationship when either side is updated.
public void addPlayer(BallPlayer aPlayer){
players.add(aPlayer);
aPlayer.setTeam(this);
}
If you still find the invert attribute and associations confusing, I encourage you to download the code for this blog post here and see if it makes more sense after you play with the setting in this simple example.
To learn more about Hibernate, consider taking Intertech's Complete Hibernate class.
Free Learning Event - Globalizing your Java App
Tuesday, August 4, 2009
Java 7 - good, bad or somewhere in between
Not sure about the new Java 7 JDK? It seems you would not be alone if you are still wavering on the new JDK (anticipated to be released in early 2010 - see my blog posting on Java 7 and Java EE 6 here). A recent poll on java.net (“The Source for Java Technology Collaboration” as deemed by Sun) indicates that almost half of 488 surveyed in the Java community (203 – 41% to be exact) don’t think it addresses “significant” problems. See the poll results and comments left by others here.
It is not a scientific survey, but the number seemed to capture some attention. In fact, the ServerSide.com noted the survey and mentioned the “Diversity of opinions on JDK 7” in its weekly email newsletter. Have you tried out the new JDK? If so, what are your thoughts? Will your organization move to Java 7 quickly or slowly. Provide your answer to my Java 7 questions at right.
Friday, July 17, 2009
Complete Hibernate – Beta Class at Reduced Price
JAX-WS and Operation Overloading
During class, we explored the JAX-WS annotations for defining Java Web services. Specifically, we looked at the @WebService annotation on the service endpoint interface (SEI) and implementation bean (SIB) as shown below.
package example;
import
javax.jws.WebService;
@WebService(endpointInterface ="example.SomeService")
public class SomeServiceImpl implements SomeService
{
public int doIt(String str) {
return 0;
}
}
package example;
import
javax.jws.WebService;
@WebService
public interface SomeService {
public
int doIt(String str);
}
package example;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
public interface SomeService {
public int doIt(String str);
@WebMethod(operationName = "doItNow")
public int doIt(int i);
}
package example;
import javax.jws.WebService;
@WebService(endpointInterface = "example.SomeService")
public class SomeServiceImpl implements SomeService {
public int doIt(String str) {
return 0;
}
public int doIt(int i) {
return 0;
}
}
The answer is – no, not easily. This will be somewhat dependent on the JAX-WS implementation (for example, take a look at Christophe Hamerling’s example in Apache CXF where overloaded operations and use of the @operationName works) and work-arounds could probably be negotiated (for example, don’t use document/literal wrapped style). However, when using the JAX-WS reference implementation mapping tools there is still going to be problems despite the @WebMethods operationName attribute provides a unique operation name as far as SOAP and WSDL are concerned.
Sunday, July 5, 2009
JAX-RS: A new Java Web service API
JAX-RS will be part of Java EE 6 which is due out in final form in September ’09. What is JAX-RS? JAX-RS is the Java API for RESTful Web Services. OK, so what is a RESTful Web service? The term REST (Representation State Transfer) dates to a 2000 doctoral dissertation by Roy Fielding – cofounder of the Apache HTTP server and coauthor of the HTTP and URI standards. REST is the software architecture (or architectural style) for distributed hypermedia (text, graphics, audio, video, etc.) systems. REST is the foundation of the World Wide Web. RESTful Web services, is the application of the REST architectural style to provide information to other systems, process, etc.
At the heart of a RESTful system is a resource. A resource is anything that has an identifier in the form of a URI. Any informational item that can be named can be a resource: stock price, customer, purchase order, calendar of events, etc. The concept of a resource is broad. Here are some examples.
http://www.intertech.com/studentDirectory/students
http://www.intertech.com/studentDirectory/students/jamesBond
http://www.intertech.com/studentDirectory/students/missMoneypenny
Resources have state and it is that state that the requester of the resource is interested. A RESTful Web service requestor or client may request to read the resource’s state. A client may request to update a resource’s state. Behind REST systems is a set of client-invoked operations on resources. While not absolutely required, most have come to accept the set of HTTP methods as the general API for REST operations on resources.
GET - Read a resourcePOST - Create/add a new resource from the
HTTP request body
PUT - Update a resource from the HTTP request body
DELETE - Delete a resource
The URI query string might provide amplifying information about the operation.
http://www.intertech.com/studentDirectory/students?lastName=Bond
In a RESTful system, URIs act as nouns (identifying resources) and the HTTP method acts as a verb that specifies the operations on the resources. URIs and HTTP methods provide, while more convention than standard, a terse and uniform style for information exchange.
So Back to JAX-RS. JAX-RS allows for the construction of RESTful services in Java. Using JAX-RS, REST resources are Plain Old Java Objects. The POJOs are annotated with @Path. @Path takes one argument. The argument identifies the relative URI path to which the resource responds.
@Path("/helloworld")
public class HelloWorldResource {
...
}
The URI path is relative to the base URI of the server the resource is deployed, the context root of the WAR, and the URL pattern for an adapter servlet that routes traffic to the resources.
http://: / / /
So, assuming the resource above was in a MyWebApp WAR, a URL request to this HelloWorldResource might look like the following:
http://localhost:8080/MyWebApp/resources/helloworld
The @Path annotation merely dictates what request traffic is sent to the resource.
Add annotations (@GET, @POST, @PUT, @DELETE, @HEAD) to the resource methods to indicate what should be invoked for each type of HTTP request.
@Path("/helloworld")
public class HelloWorldResource {
@GET
public String sayHello() {
return "Hello
World";
}
}
Methods that are annotated with @GET, @POST, @PUT, @DELETE and @HEAD are called resource methods and allow for the RESTful service clients to retrieve, update, remove, and create new resources.
By default, the resource returns text/plain. However, the @Produces annotation can be used to specify the MIME type of response. The @Produces can annotate the resource to provide the default return type for all resource methods.
@Path("/helloworld")Resources may offer multiple MIME types for any given request.
@Produces("text/html")
public class
HelloWorldResource {
...
}
Resources may also be sent information (as part of the HTTP request body) by the client. The @Consumes annotation works in a fashion similar to @Produces but for incoming rather than outgoing MIME types. @Consumes specifies which MIME types can be accepted or consumed by the resource.
@POSTAs with all Java specifications, JAX-RS must be implemented. The Jersey project is Sun’s reference implementation of JAX-RS 1.0. You can get Jersey today at https://jersey.dev.java.net. To learn more about JAX-RS and the other APIs of Java Web Services, sign up to take Intertech’s updated Complete Java Web Services class.
@Consumes("text/plain")
public void respondToMessage(String message)
{
...
}
Monday, June 15, 2009
Spring Dependency Injection Questions
I had a great group of students to help give this new class its inaugural flight. While a little on the quiet side, they had wonderful questions and some great insight at the conclusion of our class for how to improve it. I thought I would share two questions that came out this week’s class.
Question #1 (thanks Sharon) - What happens when you use
And the class looked like this…
public class Player
{
private List teams;
public void setTeams(List teams) {
this.teams = teams;
}
}
The implementation class of the collection bean property does not have to match or
Question #2 (thanks Kurt) - Another great question came when we looked at the @Autowire annotation that was added in Spring 2.5. This annotation can be used on any method in the class to conduct dependency injection. The question was what if the @Autowire is used on multiple methods to dependency inject the same property? For example…
public class Player {
private String name;
private Team team;
@Autowired
public void initializePlayer(Team team){
this.team =
team;
}
@Autowired
public void initializePlayerAgain(Team team){
this.team = team;
}
}
In fact, both methods will get called and a Team will get passed to both methods. While this works, we could not think of a good reason for its use.If you have interest in exploring Spring, please contact our office (651-994-8558) and ask for Dan McCabe. I think our Spring training is the most complete (pun absolutely intended!).
Friday, June 5, 2009
Java SE 7 and Java EE 6
Java 7 is expected to be released Feb 2010. Based on last year's conference notes and milestones released this year already, many thought (including myself) that Java 7 would be released sooner. The last feature-complete milestone is scheduled for Oct 2009. I attended a few sessions that discussed what will be in Java 7. Everyone was careful to say that the final decisions hadn't been made yet, indicating there is still work being done on Java 7. Some of the things likely to be in Java 7...
1. modules (allowing you to customize the features of Java you need for your app and finally killing the classpath)
2. null check operator/conditional - "?:"
3. Strings in switches
4. multiple exception catches in the catch block (using "")
5. diamond operator to allow the generics to be more easily used.
//For example...
HashMap
//becomes
HashMap
Things not likely to make Java 7 but at one time rumored to have a chance...
1. closures
2. SQL expression checking
Java EE 6 will actually come out sooner. Java EE 6 is due on in final form in Sept 2009. In this release, the big new features are:
1. JAX-RS (support for RESTful web services)
2. JSF 2.0
3. Asynch servlets
4. Bean validation (adding validation to JavaBeans that can be used to validate property data anytime they are used).
5. Web.xml is gone (at least it can be gone) with the use of annotations and/or web.xml fragments.
6. Web beans - essentially session beans in the WAR file.
A few other notes from the conference...
Eclipse Galileo is the next train release of Eclipse (following the previous year releases of Calisto, Europa, and Ganymede) and it will come out on June 24th. This release now includes 33-48 Eclipse projects (Ganymede included 24 projects). On Jun 26, there will be a live Webinar to learn about new features. From the talk, I wouldn't say there is any real big thing in this release that most of us would use on a regular basis.
Spring has a new project called Spring Roo (yes for kangaroo). Essentially, this is Rails or Grails but all in Java and Spring. Meta programming is here to stay folks. I hope to have more on that in a later blog posting.
Sunday, May 31, 2009
Groovy and Grails at JavaOne
The conference’s Java University started today. I attended a wonder class by Graeme Rocher on Groovy and Grails. Graeme is the project lead for Grails and head of Grails development at Spring Source.
Groovy is a programming language that has been attracting a lot of attention lately. And base on what I learned and saw today, it rightfully should. Groovy is a dynamic language inspired by a number of other such languages (most notably like Ruby, Smalltalk and Python) written specifically for the Java Virtual Machine. Its aim is to bring the “power of Ruby and Python and the elegance of the Java syntax to a JVM.” Because it is written specifically for the JVM, it is an extension to Java. Groovy provides all the power of metaprogramming but with all the benefits of Java and the JVM underneath. Although other dynamic languages like JRuby or Jython run on the JVM, they have had to be modified in order to run on the JVM. Some concessions were made in the port of Ruby and Python to the JVM. Most of the environments are an extension but a replacement of the Java API (having their own I/O and collection API for example). The goal of Groovy is simple – less code meaning faster development and hopefully easier/faster maintenance.
Grails is an MVC++ action-based web framework. Grails is to Groovy what Rails is to Ruby (more precisely Ruby on Rails). I say Grails is an MVC “plus plus” framework because it is more, way more, than just a web application framework. It also provides the entire platform for building applications from the UI to the data layer. In fact, Grails is built on Groovy (of course) as well as Spring, Spring MVC, Hibernate, Quartz (for job scheduling), SiteMesh (layout framework), Jetty and HSQLDB. Like Rails, building a CRUD (create, read, update, delete) interface can be done in minutes. But because it is also built on top of the best-of-breed Java technologies, it can also do so much more, and because it is done with Groovy, it can be done quickly with very little code.
A couple of things to consider before you start singing Kumbaya with the Grails/Groovy crowd. Grails requires a relatively up to date platform. Grails comes with its own container and even database, but most shops are going to want to run Grails on their own container. Grails requires a Web container that is at the 2.5 level (Java Servlet 2.5). Secondly, Grails is slower than Java. According to Graeme, he has seen a Java application that did ~1000 transactions a minute only perform ~750 when using Grails. The good news is that the same app using Rails did only ~150. Rails performance issues are starting to attract some attention and Grails offers the same kind of development convenience with a much better performance outlook (see http://www.infoq.com/articles/Rails-Performance or http://www.techcrunch.com/2008/05/01/twitter-said-to-be-abandoning-ruby-on-rails/ for some of the Rails issues). Lastly, Grails, while offering the promise of less code and faster development, is not a tool for novices. Under the covers of Grails and Groovy, there is a lot of Java and Java technologies. While Groovy and Grails helps abstract away many of the details and common drudgery of modern Java application development, it does not protect the developer from having to fine tune and tweak application to do the business’s bidding, especially in large scale, high performance environments. I asked Graeme if he felt developers of Grails applications needed to know Spring, Hibernate and all the underlying technologies well to be able to build a large scale performing enterprise application. He indicated that in some cases, for example Spring, developers were isolated from having to know the framework to get things to work and work well. But developers are going to have to know and understand the inner workings of other frameworks like Hibernate in order to make parts of Grails like GORM (Grail’s ORM capability) perform well. Given that Grails is built on top of Java, on top of many Java technologies like Hibernate and Spring, and on top of Groovy, this is a lot to learn and know.
Still, when you see the simplicity and speed of Groovy and Grails development, you can’t help but believe there indeed IS a better way to build Web applications. “Power to the people” with Groovy. I encourage you to take a look. More information on Groovy can be found at http://groovy.codehaus.org/. Information on Grails can be found at http://www.grails.org/.
Wednesday, May 27, 2009
New Spring Classes and a Special One-time Discount
In fact, we (Intertech) has a special offer. For the Beta (first public offering) of these two Intertech courses, we’re offering a 25% discount on the standard course rate. In exchange for the discount, you agree to give detailed course feedback. The courses and dates are:
Complete Spring Core Training, June 8-10
Complete Spring Web Training, June 11-12
To get this special pricing, you must register over the phone (651-994-8558 +23) and mention “BETA-RUN.” This is a onetime offer so sign up now.
Friday, May 15, 2009
Questions from Java "newbies"
1. In Eclipse, is there a way to run the Javadoc tool against my code? [Thanks Pradeep]
The answer is yes! While I knew this was possible, I wasn’t exactly sure of how this is done. It turns out using Javadoc from within Eclipse is a piece of cake. Given your Eclipse IDE is already configured to use the tools from a JDK, chances are good that it is already setup to generate Javadocs for your code with a simple menu selection. In Eclipse, look for the Project menu option on the Eclipse menu bar. Select Generate Javadoc… from the Project pull-down menu.
This should cause the Generate Javadoc window to open where you can specify what members should be included (private up to public) and where the documents generated should be put. If the JDK’s bin folder and/or the javadoc.exe tool can’t be found, the same window allows you to point Eclipse to a valid Javadoc generating tool and configure it per your needs.
Once the Javadocs are created, the documents are used by Eclipse to produce hovers over the classes, methods, variables, etc.
2. Can a list of stored procedures in a database be obtained from JDBC’s DatabaseMetaData class? [Thanks Bill]
Again the answer is yes! A DatabaseMetaData object provides all sorts of information about the database and database driver. The DatabaseMetaData interface defines 40+ fields and 100+ methods. The DatabaseMetaData object includes data about what schemas and tables are defined in the database. It allows developers to determine database capabilities programmatically, such as whether the database supports column aliasing. It also includes information such as the database name and version. To get a DatabaseMetaData object, request it from the JDBC Connection object.
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root");
DatabaseMetaData md = conn.getMetaData();
With a DatabaseMetaData object, you can get the list of stored procedures from the database (provided your database supports stored procedures) by calling ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) on the DatabaseMetaData object. The ResultSet that is returned contains columns of data (listed below per the JDBC documentation) that describe the stored procedures.
· PROCEDURE_CAT String => procedure catalog (may be null)
· PROCEDURE_SCHEM String => procedure schema (may be null)
· PROCEDURE_NAME String => procedure name
· reserved for future use
· reserved for future use
· reserved for future use
· REMARKS String => explanatory comment on the procedure
· PROCEDURE_TYPE short => kind of procedure:
· procedureResultUnknown - Cannot determine if a return value will be returned
· procedureNoResult - Does not return a return value
· procedureReturnsResult - Returns a return value
· SPECIFIC_NAME String => The name which uniquely identifies this procedure within its schema.
Wednesday, May 6, 2009
Free Expression Blend Presentation
We’ll cap the registrations for the event at Microsoft at 120 and over the web at 250. Both will fill. If you’re interested, beat the pack and register today:
Live At Microsoft: click here
Live Over the Web: click here.
Spring Stereotype Components
http://www.devx.com/Java/Article/41629
Haven't had a chance to learn Spring yet? Come take our Intertech classes on Spring: Complete Spring Core and Complete Spring Web. We offer classes on-site as well as virtually.
Tuesday, April 21, 2009
Intertech Podcasts
Look for Podcasts and Youtube presentations on my JavaFX talk soon.
DevX articles
The first on the introduction of JavaFX Mobile: http://www.devx.com/Java/Article/41395
The second is on the new (and consolidated) JavaME SDK 3.0: http://www.devx.com/Java/Article/41505
Oracle buys Sun
Wednesday, April 15, 2009
IBM and Sun - NOT
the Guardian UK.
Free Training Event
Here’s more info:
Date: 5/26/2009
Time: 9:00 AM - 11:00 PM
Location: Held at Microsoft Corporation, Bloomington, MN
Description: If you are creating WPF or Silverlight applications, you have most certainly wondered about Expression Blend. While it is true that this tool is geared towards graphical artists, software engineers can also use this tool to simplify their XAML creation efforts. In this talk, attendees learn the mechanics of working with Blend to author a UI, create animations, generate application resources, and establish data binding operations. During the process, numerous bits of XAML are clarified. No artistic experience required.
To register: https://www.clicktoattend.com/invitation.aspx?code=135487
Tuesday, March 31, 2009
IBM and Sun Merger?
While this may or may not impact your financial portfolio, it could definitely start to impact the technological landscape - especially as it relates to Java developers. Since the news broke back on March 19 (http://online.wsj.com/article/SB123735124997967063.html?mod=sphere_ts&mod=sphere_wd) there has been little new information. Heidi Moore from the Wall Street Journal has blogged about this and its possible meaning (see http://blogs.wsj.com/digits/2009/03/31/ibm-sun-do-they-have-a-deal-does-it-matter/).
I am not a financial expert nor enough of a business analyst to know long term how such a merger will impact our Java community. But there are a long list of questions we should keep in mind should such an event happen. I've noted some below. Perhaps you have others...
What happens to the Java platform and the Java Community Process which helps guide its direction?
- What happens to the more recent open source efforts that have occurred with Java? Would IBM maintain that direction?
- What does IBM control of Java mean for all the container providers (BEA, Oracle, JBoss, etc.), tool and API vendors?
- How does an IBM-led application platform compete with Microsoft?
- Many have suggested Sun is a company on the ropes. Initial indications are that IBM is willing to pay a bit of a premium for Sun. So what's the purpose of an IBM takeover - to avoid having Java and other Sun technology fall into the wrong hands or to take Java someplace it hasn't been before? If so, where is that?
At this point, many more questions than answers, but we should all stay tuned and on alert. The impact could be big for all of us.
Wednesday, March 25, 2009
JavaFX - the Java UI of the future?
What is JavaFX? It is a rich Internet application (RIA) technology that runs on any JVM. It is meant to provide “all the screens of your life” as Sun likes to say; from desktop to mobile handheld to consumer device. Take a look at the sample application I wrote for an upcoming talk… as seen on the desktop, via Web Start, on a browser and in a mobile emulator.
JavaFX is a new scripting language based on Java, JavaScript, scalar vector graphics among other languages. JavaFX is and will continue to compete with Ajax, Adobe Flex, Microsoft Silverlight and other RIA technologies. It is a late comer to the RIA game. Some question if it might be too late to the game. Time will tell.
So why should you examine it? Unlike many of the other RIA technologies, JavaFX is not just for desktops. It again is designed for all the user interfaces/device screens that users encounter. While Java has always espoused to WORA, JavaFX has a chance to really bring WORA to the thousands of screens/UIs that Java supports. It also leverages the entire Java API. While JavaFX is its own scripting language, a JavaFX script can call on other Java classes and vice versa. Also, JavaFX apps run on the JVM. Finally, because it is like Java and JavaScript, it should be easy to learn and use. JavaFX is a declarative, expression, full object-oriented language.
Below are a few links to help you get going. Also, I will be presenting a free talk on JavaFX at Intertech on April 14th. You can sign up on our web site at http://www.intertech.com/resource/briefings.aspx. For those not located in the Twin Cities (Minnesota) area, the talk will also be offered from the virtual classroom so come join in the fun.
Lastly, look for my upcoming paper on JavaFX Mobile at DevX.com (http://www.devx.com/).
Some links you can use to explore JavaFX
JavaFX Website (Overview, FAQ, download): http://javafx.com/
JavaFX SDK version 1.1: http://javafx.com/downloads
Sun's JavaFX tutorial site: http://java.sun.com/javafx/1/tutorials/core/index.html
Free JavaFX tutorial offered online: http://www.javapassion.com/javafx/
Sun JavaFX building GUI tutorial: http://java.sun.com/javafx/1/tutorials/ui/index.html
JavaFX API Javadocs: http://java.sun.com/javafx/1.1/docs/api/
JavaFX language reference: http://openjfx.java.sun.com/current-build/doc/reference/JavaFXReference.html
JavaFX Blog: http://learnjavafx.typepad.com/weblog/2008/02/getting-plutoed.html
Monday, February 23, 2009
A new and united Java ME SDK
Based on an email from Radko Najman, the final release of the product should be available by JavaOne 2009. In fact, he indicated they hope to have a final release out by March or April.
Find out more about this new SDK at http://java.sun.com/javame/downloads/sdk30ea.jsp. Also, look for my upcoming article on the SDK on http://www.DevX.com.
Wednesday, February 4, 2009
The Eclipse Classpath
Eclipse, and most integrated development environments (IDEs), are that way. It is an extremely powerful tool in the right hands. In the hands of a novice, sometimes it can be overwhelming.
Novice Java developers are taught about the classpath in their first days or hours of learning the Java programming language. When using java.exe and javac.exe command line tools, the classpath is usually transparent or can be made transparent with a simple call to setenv. When developers step up to an IDE, what the classpath is and what it points to isn’t so clear anymore. So, if you are just learning Java and need some help on the where to set and get information on the classpath, this posting is for you!
By the way, take heart. The reason I make this post is because so many of my students have had questions about the classpath or wrestled with problems due to the classpath setting in the IDE that I felt compelled to write this post in hopes of alleviating some future student’s pain. So you are not alone.
Maybe one of the largest issues with classpath and Eclipse is that there are so many places to set and affect the classpath. So, let’s address them one at a time.
The Project Properties
First, start Eclipse and right click on a project folder in the Package Explorer view. Select Properties from the menu that results.
A Properties window like that shown below will appear.
Select Java Build Path from the menu on the left hand side. A series of tabs (Source, Projects, Libraries, Order and Export) appear. It is on these tabs that you can set the “build” classpath. That is, you can set where Java will find class files, Jar files and other resources when it is compiling (building) your application. The Source tab allows you to specify folders of source code (typically folders containing the packages and .java files for your project). The Projects tab allows you to include the code from other Eclipse projects into the building. Finally, the Libraries tab allows you to specify libraries of classes to add to your build – either external or internal to Eclipse.
Selecting the Add JARs button on this tab allows you to add a Java library (JAR or ZIP file of classes) that is known to Eclipse (that is part of an open Eclipse project). The Add External JARs button allows you to add a Java library that is available via your computer’s file system or network (essentially any library reachable by your machine). The Add Library button allows you to add the classes (via Java library) of a Java/Eclipse plug-in, tool (like JUnit), or framework (like Struts or JSF) that is known and installed with Eclipse.
The Add Class Folder button allows you to add the classes from any folder of any project that is open in Eclipse.
And of course the Add External Class Folder button allows you to add classes from any folder on your computer’s file system or network to your build. I skipped one button; the Add Variable button. That’s covered in the next section.
By the way, as a short cut, you can also adjust the build path by right clicking on a project in the Package Explorer view and selecting Build Path from the menu.
Variables
So what does the variable button do? If you click on it, you’ll see you can add a variable to the build path but what does that mean?
Close the project properties window and return to the Eclipse window. In Eclipse, select the Window > Preferences menu option on the menu bar.
In the Preferences window that appears, locate the Java > Build Path > Classpath Variable option in the menu on the left (see the image below, it can be a little tricky to find in this large menu.
A classpath variable allows you to define a variable or alias to a folder with class files or a specific JAR file. Then, the variable can simply be added to the classpath of either the build or runtime configuration (see below). A variable helps you easily refer to a particular library without having to remember where it is. Also, it allows the location to change without having to change the project – just change the variable’s path. This can be particularly useful if the library is shared by several projects.
The Runtime Configuration
The classes that are available to build the application are not always the same as the classes available to run the application. When you are ready to run your application, most people just click on the Run As or Debug As icons in the Eclipse toolbar; unaware that Eclipse is setting up an environment complete with a classpath to execute your code. When you run or debug your application, Eclipse sets up what is called a runtime configuration. That configuration includes a classpath telling the Java VM where it should locate classes, libraries, etc. needed as the application is executed. You can modify this execution or runtime classpath as well.
Right click on one of your executable classes or projects in the Package Explorer view. Select either the Run As… or Debug As… option from the menu that appears. From the sub-menu that appears, notice the Run Configurations… or Debug Configurations… option that is presented.
Select the Run Configurations… option and a Run Configurations window like the one shown below should appear.
In the menu on the left hand side, find the Java Application listing. These are your runtime configurations. By default, the name of the configuration usually matches the name of your executing class. In the Main tab to the right, notice the “Main class” field. This is the class that is going to be executed when you request your project or class “Run As…” Click on the Classpath tab and you see a display similar to that below.
By expanding the entry trees, you can see all the file folders and libraries that are part of the runtime classpath and are accessible to your application as it is execute. Again, with the buttons on this window, you can choose to add or remove file folders and libraries (internal or external JAR or ZIP files) to the classpath. By default, the runtime classpath should contain the same file folders and libraries as your build path.
A classpath checker
For those that find they have some issues with duplicate classes or classes not found, you may want to take a look at the Classpath Checker Eclipse plug-in (available here).
This tool will detect missing JAR files and help detect if you have classes coming from more than one location (duplicate classes).
Hope this helps developers trying to untangle the mystery of classpath in Eclipse. If you need help learning Java or other open source technology, come join me in class (www.intertech.com).