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

The Latest Coding Topics

article thumbnail
Memory Leak Protection in Tomcat 7
In this exclusive interview with DZone, Thomas elaborates on these fixes coming in the next version of Apache Tomcat.
February 1, 2010
by Mitch Pronschinske
· 86,350 Views · 1 Like
article thumbnail
Reloading Java Classes: Classloaders in Web Development — Tomcat, GlassFish, OSGi, Tapestry 5
In this article we’ll review how dynamic classloaders are used in real servers, containers and frameworks to reload Java classes and applications. We’ll also touch on how to get faster reloads and redeploys by using them in optimal ways. RJC101: Objects, Classes and ClassLoaders RJC201: How do ClassLoader leaks happen? RJC301: Classloaders in Web Development — Tomcat, GlassFish, OSGi, Tapestry 5 and so on RJC401: HotSwap and JRebel — what do they really do? RJC501: The impact of the redeploy phase on the development process AKA:Turnaround Java EE (web) applications In order for a Java EE web application to run, it has to be packaged into an archive with a .WAR extension and deployed to a servlet container like Tomcat. This makes sense in production, as it gives you a simple way to assemble and deploy the application, but when developing that application you usually just want to edit the application’s files and see the changes in the browser. A Java EE enterprise application has to be packaged into an archive with an .EAR extension and deployed to an application container. It can contain multiple web applications and EJB modules, so it often takes a while to assemble and deploy it. Recently, 1100+ EE developers told us how much time it takes them, and we compiled the results into the Redeploy and Restart Report. Spoiler: Avg redeploy & restart time is 2.5 minutes – which is higher than we expected. In Reloading Java Classes 101, we examined how dynamic classloaders can be used to reload Java classes and applications. In this article we will take a look at how servers and frameworks use dynamic classloaders to speed up the development cycle. We’ll use Apache Tomcat as the primary example and comment when behavior differs in other containers (Tomcat is also directly relevant for JBoss and GlassFish as these containers embed Tomcat as the servlet container). Redeployment To make use of dynamic classloaders we must first create them. When deploying your application, the server will create one classloader for each application (and each application module in the case of an enterprise application). The classloaders form a hierarchy as illustrated: In Tomcat each .WAR application is managed by an instance of the StandardContext class that creates an instance of WebappClassLoader used to load the web application classes. When a user presses “reload” in the Tomcat Manager the following will happen: StandardContext.reload() method is called The previous WebappClassLoader instance is replaced with a new one All reference to servlets are dropped New servlets are created Servlet.init() is called on them Calling Servlet.init() recreates the “initialized” application state with the updated classes loaded using the new classloader instance. The main problem with this approach is that to recreate the “initialized” state we run the initialization from scratch, which usually includes loading and processing metadata/configuration, warming up caches, running all kinds of checks and so on. In a sufficiently large application this can take many minutes, but in a in small application this often takes just a few seconds and is fast enough to seem instant, as commonly demonstrated in the Glassfish v3 promotional demos. If your application is deployed as an .EAR archive, many servers allow you to also redeploy each application module separately, when it is updated. This saves you the time you would otherwise spend waiting for non-updated modules to reinitialize after the redeployment. Hot Deployment Web containers commonly have a special directory (e.g. “webapps” in Tomcat, “deploy” in JBoss) that is periodically scanned for new web applications or changes to the existing ones. When the scanner detects that a deployed .WAR is updated, the scanner causes a redeploy to happen (in Tomcat it calls the StandardContext.reload() method). Since this happens without any additional action on the user’s side it is commonly referred to “Hot Deployment”. Hot Deployment is supported by all wide-spread application servers under different names: autodeployment, rapid deployment, autopublishing, hot reload, and so on. In some containers, instead of moving the archive to a predefined directory you can configure the server to monitor the archive at a specific path. Often the redeployment can be triggered from the IDE (e.g. when the user saves a file) thus reloading the application without any additional user involvement. Although the application is reloaded transparently to the user, it still takes the same amount of time as when hitting the “Reload” button in the admin console, so code changes are not immediately visible in the browser, for example. Another problem with redeployment in general and hot deployment in particular is classloader leaks. As we reviewed in Reloading Java Classes 201, it is amazingly easy to leak a classloader and quickly run out of heap causing an OutOfMemoryError. As each deployment creates new classloaders, it is common to run out of memory in just a few redeploys on a large enough application (whether in development or in production). Exploded Deployment An additional feature supported by the majority of web containers is the so called “exploded deployment”, also known as “unpackaged” or “directory” deployment. Instead of deploying a .WAR archive, one can deploy a directory with exactly the same layout as the .WAR archive: Why bother? Well, packaging an archive is an expensive operation, so deploying the directory can save quite a bit of time during build. Moreover, it is often possible to set up the project directory with exactly the same layout as the .WAR archive. This means an added benefit of editing files in place, instead of copying them to the server. Unfortunately, as Java classes cannot be reloaded without a redeploy, changing a .java file still means waiting for the application to reinitialize. With some servers it makes sense to find out exactly what triggers the hot redeploy in the exploded directory. Sometimes the redeploy will be triggered only when the “web.xml” timestamp changes, or as in the case of GlassFish only when a special ”.reload” file timestamp changes. In most servers any change to deployment descriptors or compiled classes will cause a hot redeploy. If your server only supports deploying by copying to a special directory (e.g. Tomcat “webapps”, JBoss “deploy” directories) you can skip the copying by creating a symlink from that special directory to your project workspace. On Linux and Mac OS X you can use the common “ln -s” command to do that, whereas on Windows you should download the Sysinternals “junction” utility. If you use Maven, then it’s quite complicated to set up exploded development from your workspace. If you have a solo web application you can use the Maven Jetty plugin, which uses classes and resources directly from Maven source and target project directories. Unfortunately, the Maven Jetty plugin does not support deploying multiple web applications, EJB modules or EARs so in the latter case you’re stuck doing artifact builds. Session Persistence Since we’re on the topic of reloading classes, and redeploying involves reinitializing an application, it makes sense to talk about session state. An HTTP session usually holds information like login credentials and conversational state. Losing that session when developing a web application means spending time logging in and browsing to the changes page – something that most web containers have tried to solve by serializing all of the objects in the HttpSession map and then deserializing them in the new classloader. Essentially, they copy all of the session state. This requires that all session attributes implement Serializable (ensuring session attributes can be written to a database or a file for later use), which is not restricting in most cases. Session persistence has been present in most major containers for many years (e.g. Restart Persistence in Tomcat), but was notoriously absent in Glassfish before v3. OSGi There is a lot of misunderstanding surrounding what exactly OSGi does and doesn’t do. If we ignore the aspects irrelevant to the current issue, OSGi is basically a collection of modules each wrapped in its own classloader, which can be dropped and recreated at will. When it’s recreated, the modules are reinitialized exactly the same way a web application is. The difference between OSGi and a web container is that OSGi is something that is exposed to your application, that you use to split your application into arbitrarily small modules. Therefore, by design, these modules will likely be much smaller than the monolithic web applications we are used to building. And since each of these modules is smaller and we can “redeploy” them one-by-one, re-initialization takes less time. The time depends on how you design your application (and can still be significant). Tapestry 5, RIFE & Grails Recently, some web frameworks, such as Tapestry 5, RIFE and Grails, have taken a different approach, taking advantage of the fact that they already need to maintain application state. They’ll ensure that state will be serializable, or otherwise easily re-creatable, so that after dropping a classloader, there is no need to reinitialize anything. This means that application developers use frameworks’ components and the lifecycle of those components is handled by the framework. The framework will initialize (based on some configuration, either xml or annotation based), run and destroy the components. As the lifecycle of the components is managed by the framework, it is easy to recreate a component in a new classloader without user intervention and thus create the effect of reloading code. In the background, the old component is destroyed (classloader is dropped) and a new one created (in a new classloader where the classes are read in again) and the old state is either deserialized or created based on the configuration. This has the obvious advantage of being very quick, as components are small and the classloaders are granular. Therefore the code is reloaded instantly, giving a smooth experience in developing the application. However such an approach is not always possible as it requires the component to be completely managed by the framework. It also leads to incompatibilities between the different class versions causing, among others, ClassCastExceptions. We’ve Covered a Lot – and simplified along the way It’s worth mentioning that using classloaders for code reloading really isn’t as smooth as we have described here – this is an introductory article series. Especially with the more granular approaches (such as frameworks that have per component classloaders, manual classloader dropping and recreating, etc), when you start getting a mixture of older and newer classes all hell can break loose. You can hold all kinds of references to old objects and classes, which will conflict with the newly loaded ones (a common problem is getting a ClassCastException), so watch what you’re doing along the way. As a side note: Groovy is actually somewhat better at handling this, as all calls through the Meta-Object Protocol are not subject to such problems. This article addressed the following questions: How are dynamic classloaders used to reload Java classes and applications? How do Tomcat, GlassFish (incl v3), and other servers reload Java classes and applications? How does OSGi improve reload and redeploy times? How do frameworks (incl Tapestry 5, RIFE, Grails) reload Java classes and applications? Coming up next, we continue our explanation of classloaders and the redeploy process with an investigation into HotSwap and JRebel, two tools used to reduce time spent reloading and redeploying. Stay tuned! From http://www.zeroturnaround.com/blog/
January 23, 2010
by Dave Booth
· 26,233 Views
article thumbnail
Useful U.S. Airport/City Codes In HTML Drop Down List Format
// Drop down list of Airport code in HTML. Sorted Alphabetically. Aberdeen, SD (ABR) Abilene, TX (ABI) Adak Island, AK (ADK) Akiachak, AK (KKI) Akiak, AK (AKI) Akron/Canton, OH (CAK) Akuton, AK (KQA) Alakanuk, AK (AUK) Alamogordo, NM (ALM) Alamosa, CO (ALS) Albany, NY (ALB) Albany, OR - Bus service (CVO) Albany, OR - Bus service (QWY) Albuquerque, NM (ABQ) Aleknagik, AK (WKK) Alexandria, LA (AEX) Allakaket, AK (AET) Allentown, PA (ABE) Alliance, NE (AIA) Alpena, MI (APN) Altoona, PA (AOO) Amarillo, TX (AMA) Ambler, AK (ABL) Anaktueuk, AK (AKP) Anchorage, AK (ANC) Angoon, AK (AGN) Aniak, AK (ANI) Anvik, AK (ANV) Appleton, WI (ATW) Arcata, CA (ACV) Arctic Village, AK (ARC) Asheville, NC (AVL) Ashland, KY/Huntington, WV (HTS) Aspen, CO (ASE) Athens, GA (AHN) Atka, AK (AKB) Atlanta, GA (ATL) Atlantic City, NJ (AIY) Atqasuk, AK (ATK) Augusta, GA (AGS) Augusta, ME (AUG) Austin, TX (AUS) Bakersfield, CA (BFL) Baltimore, MD (BWI) Bangor, ME (BGR) Bar Harbour, ME (BHB) Barrow, AK (BRW) Barter Island, AK (BTI) Baton Rouge, LA (BTR) Bay City, MI (MBS) Beaumont/Port Arthur, TX (BPT) Beaver Creek, CO - Van service (ZBV) Beaver, AK (WBQ) Beckley, WV (BKW) Bedford, MA (BED) Belleville, IL (BLV) Bellingham, WA (BLI) Bemidji, MN (BJI) Benton Harbor, MI (BEH) Bethel, AK (BET) Bethlehem, PA (ABE) Bettles, AK (BTT) Billings, MT (BIL) Biloxi/Gulfport, MS (GPT) Binghamton, NY (BGM) Birch Creek, AK (KBC) Birmingham, AL (BHM) Bismarck, ND (BIS) Block Island, RI (BID) Bloomington, IL (BMI) Bluefield, WV (BLF) Boise, ID (BOI) Boston, MA (BOS) Boulder, CO - Bus service (XHH) Boulder, CO - Hiltons Har H (WHH) Boulder, CO - Municipal Airport (WBU) Boundary, AK (BYA) Bowling Green, KY (BWG) Bozeman, MT (BZN) Bradford, PA (BFD) Brainerd, MN (BRD) Brawnwood, TX (BWD) Breckenridge, CO - Van service (QKB) Bristol, VA (TRI) Brookings, SD (BKX) Brooks Lodge, AK (RBH) Brownsville, TX (BRO) Brunswick, GA (BQK) Buckland, AK (BKC) Buffalo, NY (BUF) Bullhead City/Laughlin, AZ (IFP) Burbank, CA (BUR) Burlington, IA (BRL) Burlington, VT (BTV) Butte, MT (BTM) Canton/Akron, OH (CAK) Cape Girardeau, MO (CGI) Cape Lisburne, AK (LUR) Cape Newenham, AK (EHM) Carbondale, IL (MDH) Carlsbad, CA (CLD) Carlsbad, NM (CNM) Carmel, CA (MRY) Casper, WY (CPR) Cedar City, UT (CDC) Cedar Rapids, IA (CID) Central, AK (CEM) Chadron, NE (CDR) Chalkyitsik, AK (CIK) Champaign/Urbana, IL (CMI) Charleston, SC (CHS) Charleston, WV (CRW) Charlotte, NC (CLT) Charlottesville, VA (CHO) Chattanooga, TN (CHA) Chefornak, AK (CYF) Chevak, AK (VAK) Cheyenne, WY (CYS) Chicago, IL - All airports (CHI) Chicago, IL - Midway (MDW) Chicago, IL - O'Hare (ORD) Chicken, AK (CKX) Chico, CA (CIC) Chignik, AK - Fisheries (KCG) Chignik, AK - (KCQ) Chignik, AK - Lagoon (KCL) Chisana, AK (CZN) Chisholm/Hibbing, MN (HIB) Chuathbaluk, AK (CHU) Cincinnati, OH (CVG) Circle Hot Springs, AK (CHP) Circle, AK (IRC) Clarks Point, AK (CLP) Clarksburg, WV (CKB) Clearwater/St Petersburg, FL (PIE) Cleveland, OH (CLE) Clovis, NM (CVN) Cody/Yellowstone, WY (COD) Coffee Point, AK (CFA) Coffman Cove, AK (KCC) Cold Bay, AK (CDB) College Station, TX (CLL) Colorado Springs, CO (COS) Columbia, MO (COU) Columbia, SC (CAE) Columbus, GA (CSG) Columbus, MS (GTR) Columbus, OH (CMH) Concord, CA (CCR) Concordia, KS (CNK) Copper Mountain, CO - Van service (QCE) Cordova, AK (CDV) Corpus Christi, TX (CRP) Cortez, CO (CEZ) Craig, AK (CGA) Crescent City, CA (CEC) Crooked Creek, AK (CKO) Cube Cove, AK (CUW) Cumberland, MD (CBE) Dallas, TX - Love Field (DAL) Dallas, TX - Dallas/Ft Worth Intl. (DFW) Dayton, OH (DAY) Daytona Beach, FL (DAB) Decatur, IL (DEC) Deering, AK (DRG) Del Reo, TX (DRT) Delta Junction, AK (DJN) Denver, CO - International (DEN) Denver, CO - Longmont Bus service (QWM) Des Moines, IA (DSM) Detroit, MI - All airports (DTT) Detroit, MI - Metro/Wayne County (DTW) Devil's Lake, ND (DVL) Dickinson, ND (DIK) Dillingham, AK (DLG) Dodge City, KS (DDC) Dothan, AL (DHN) Dubois, PA (DUJ) Dubuque, IA (DBQ) Duluth, MN (DLH) Durango, CO (DRO) Durham, NC (RDU) Durham/Raleigh, NC (RDU) Dutch Harbor, AK (DUT) Easton, PA (ABE) Eau Claire, WI (EAU) Edna Bay, AK (EDA) Eek, AK (EEK) Ekuk, AK (KKU) Ekwok, AK (KEK) El Centro, CA (IPL) El Dorado, AR (ELD) El Paso, TX (ELP) Elfin Cove, AK (ELV) Elim, AK (ELI) Elko, NV (EKO) Elmira, NY (ELM) Ely, MN (LYU) Emmonak, AK (EMK) Endicott, NY (BGM) Enid, OK (WDG) Erie, PA (ERI) Escanaba, MI (ESC) Eugene, OR (EUG) Eureka/Arcata, CA (ACV) Eureka, NV (EUE) Evansville, IN (EVV) Fairbanks, AK (FAI) Fargo, ND (FAR) Farmington, NM (FMN) Fayetteville, AR - Municipal/Drake (FYV) Fayetteville, AR - Northwest Arkansas Regional (XNA) Fayetteville, NC (FAY) Flagstaff, AZ (FLG) Flint, MI (FNT) Florence, SC (FLO) Florence/Muscle Shoals/Sheffield, AL (MSL) Fort Collins/Loveland, CO - Municipal Airport (FNL) Fort Collins/Loveland, CO - Bus service (QWF) Fort Dodge, IA (FOD) Fort Lauderdale, FL (FLL) Fort Leonard Wood, MO (TBN) Fort Myers, FL (RSW) Fort Smith, AR (FSM) Fort Walton Beach, FL (VPS) Fort Wayne, IN (FWA) Fort Worth/Dallas, TX (DFW) Franklin, PA (FKL) Fresno, CA (FAT) Gainesville, FL (GNV) Gallup, NM (GUP) Garden City, KS (GCK) Gary, IN (GYY) Gillette, WY (GCC) Gladewater/Kilgore, TX (GGG) Glasgow, MT (GGW) Glendive, MT (GDV) Golovin, AK (GLV) Goodnews Bay, AK (GNU) Grand Canyon, AZ - Heliport (JGC) Grand Canyon, AZ - National Park (GCN) Grand Forks, ND (GFK) Grand Island, NE (GRI) Grand Junction, CO (GJT) Grand Rapids, MI (GRR) Grand Rapids, MN (GPZ) Grayling, AK (KGX) Great Falls, MT (GTF) Green Bay, WI (GRB) Greensboro, NC (GSO) Greenville, MS (GLH) Greenville, NC (PGV) Greenville/Spartanburg, SC (GSP) Groton/New London, CT (GON) Gulfport, MS (GPT) Gunnison, CO (GUC) Gustavus, AK (GST) Hagerstown, MD (HGR) Hailey, ID (SUN) Haines, AK (HNS) Hampton, VA (PHF) Hana, HI - Island of Maui (HNM) Hanapepe, HI (PAK) Hancock, MI (CMX) Hanover, NH (LEB) Harlingen, TX (HRL) Harrisburg, PA (MDT) Harrison, AR (HRO) Hartford, CT (BDL) Havasupai, AZ (HAE) Havre, MT (HVR) Hayden, CO (HDN) Hays, KS (HYS) Healy Lake, AK (HKB) Helena, MT (HLN) Hendersonville, NC (AVL) Hibbing/Chisholm, MN (HIB) Hickory, NC (HKY) High Point, NC (GSO) Hilo, HI - Island of Hawaii (ITO) Hilton Head, SC (HHH) Hobbs, NM (HBB) Hollis, AK (HYL) Holy Cross, AK (HCR) Homer, AK (HOM) Honolulu, HI - Island of Oahu (HNL) Hoolehua, HI - Island of Molokai (MKK) Hoonah, AK (HNH) Hooper Bay, AK (HPB) Hot Springs, AR (HOT) Houston, TX - All airports (HOU) Houston, TX - Hobby (HOU) Houston, TX - Intercontinental (IAH) Hughes, AK (HUS) Huntington, WV/Ashland, KY (HTS) Huntsville, AL (HSV) Huron, SD (HON) Huslia, AK (HSL) Hyannis, MA (HYA) Hydaburg, AK (HYG) Idaho Falls, ID (IDA) Igiugig, AK (IGG) Iliamna, AK (ILI) Imperial, CA (IPL) Indianapolis, IN (IND) International Falls, MN (INL) Inyokern, CA (IYK) Iron Mountain, MI (IMT) Ironwood, MI (IWD) Islip, NY (ISP) Ithaca, NY (ITH) Jackson Hole, WY (JAC) Jackson, MS (JAN) Jackson, TN (MKL) Jacksonville, FL (JAX) Jacksonville, NC (OAJ) Jamestown, ND (JMS) Jamestown, NY (JHW) Janesville, WI (JVL) Johnson City, NY (BGM) Johnson City, TN (TRI) Johnstown, PA (JST) Jonesboro, AR (JBR) Joplin, MO (JLN) Juneau, AK (JNU) Kahului, HI - Island of Maui, (OGG) Kake, AK (KAE) Kakhonak, AK (KNK) Kalamazoo, MI (AZO) Kalaupapa, HI - Island of Molokai, (LUP) Kalskag, AK (KLG) Kaltag, AK (KAL) Kamuela, HI - Island of Hawaii, (MUE) Kansas City, MO (MCI) Kapalua, HI - Island of Maui, (JHM) Kasaan, AK (KXA) Kasigluk, AK (KUK) Kauai Island/Lihue, HI (LIH) Kearney, NE (EAR) Keene, NH (EEN) Kenai, AK (ENA) Ketchikan, AK (KTN) Key West, FL (EYW) Keystone, CO - Van service (QKS) Kiana, AK (IAN) Kilgore/Gladewater, TX (GGG) Killeen, TX (ILE) King Cove, AK (KVC) King Salmon, AK (AKN) Kingman, AZ (IGM) Kingsport, TN (TRI) Kipnuk, AK (KPN) Kirksville, MO (IRK) Kivalina, AK (KVL) Klamath Falls, OR (LMT) Klawock, AK (KLW) Knoxville, TN (TYS) Kobuk, AK (OBU) Kodiak, AK (ADQ) Kona, HI - Island of Hawaii (KOA) Kongiganak, AK (KKH) Kotlik, AK (KOT) Kotzebue, AK (OTZ) Koyukuk, AK (KYU) Kwethluk, AK (KWT) Kwigillingok, AK (KWK) La Crosse, WI (LSE) Lafayette, IN (LAF) Lafayette, LA (LFT) Lake Charles, LA (LCH) Lake Havasu City, AZ (HII) Lake Minchumina, AK (LMA) Lanai City, HI - Island of Lanai (LNY) Lancaster, PA (LNS) Lansing, MI (LAN) Laramie, WY (LAR) Laredo, TX (LRD) Las Vegas, NV (LAS) Latrobe, PA (LBE) Laurel, MS (PIB) Lawton, OK (LAW) Lebanon, NH (LEB) Levelock, AK (KLL) Lewisburg, WV (LWB) Lewiston, ID (LWS) Lewistown, MT (LWT) Lexington, KY (LEX) Liberal, KS (LBL) Lihue, HI - Island of Kaui (LIH) Lincoln, NE (LNK) Little Rock, AR (LIT) Long Beach, CA (LGB) Longview, TX (GGG) Lopez Island, WA (LPS) Los Angeles, CA (LAX) Louisville, KY (SDF) Loveland/Fort Collins, CO - Municipal Airport (FNL) Loveland/Fort Collins, CO - Bus service (QWF) Lubbock, TX (LBB) Macon, GA (MCN) Madison, WI (MSN) Madras, OR (MDJ) Manchester, NH (MHT) Manhattan, KS (MHK) Manistee, MI (MBL) Mankato, MN (MKT) Manley Hot Springs, AK (MLY) Manokotak, AK (KMO) Marietta, OH/Parkersburg, WV (PKB) Marion, IL (MWA) Marquette, MI (MQT) Marshall, AK (MLL) Martha's Vineyard, MA (MVY) Martinsburg, PA (AOO) Mason City, IA (MCW) Massena, NY (MSS) Maui, HI (OGG) Mcallen, TX (MFE) Mccook, NE (MCK) Mcgrath, AK (MCG) Medford, OR (MFR) Mekoryuk, AK (MYU) Melbourne, FL (MLB) Memphis, TN (MEM) Merced, CA (MCE) Meridian, MS (MEI) Metlakatla, AK (MTM) Meyers Chuck, AK (WMK) Miami, FL - International (MIA) Miami, FL - Sea Plane Base (MPB) Midland, MI (MBS) Midland/Odessa, TX (MAF) Miles City, MT (MLS) Milwaukee, WI (MKE) Minneapolis, MN (MSP) Minot, ND (MOT) Minto, AK (MNT) Mission, TX (MFE) Missoula, MT (MSO) Moab, UT (CNY) Mobile, AL (MOB) Modesto, CA (MOD) Moline, IL (MLI) Monroe, LA (MLU) Monterey, CA (MRY) Montgomery, AL (MGM) Montrose, CO (MTJ) Morgantown, WV (MGW) Moses Lake, WA (MWH) Mountain Home, AR (WMH) Mountain Village, AK (MOU) Muscle Shoals, AL (MSL) Muskegon, MI (MKG) Myrtle Beach, SC (MYR) Nantucket, MA (ACK) Napakiak, AK (WNA) Napaskiak, AK (PKA) Naples, FL (APF) Nashville, TN (BNA) Naukiti, AK (NKI) Nelson Lagoon, AK (NLG) New Chenega, AK (NCN) New Haven, CT (HVN) New Koliganek, AK (KGK) New London/Groton (GON) New Orleans, LA (MSY) New Stuyahok, AK (KNW) New York, NY - All airports (NYC) New York, NY - Kennedy (JFK) New York, NY - La Guardia (LGA) Newark, NJ (EWR) Newburgh/Stewart Field, NY (SWF) Newport News, VA (PHF) Newtok, AK (WWT) Nightmute, AK (NME) Nikolai, AK (NIB) Nikolski, AK (IKO) Noatak, AK (WTK) Nome, AK (OME) Nondalton, AK (NNL) Noorvik, AK (ORV) Norfolk, NE (OFK) Norfolk, VA (ORF) North Bend, OR (OTH) North Platte, NE (LBF) Northway, AK (ORT) Nuiqsut, AK (NUI) Nulato, AK (NUL) Nunapitchuk, AK (NUP) Oakland, CA (OAK) Odessa/Midland, TX (MAF) Ogdensburg, NY (OGS) Oklahoma City, OK (OKC) Omaha, NE (OMA) Ontario, CA (ONT) Orange County, CA (SNA) Orlando, FL - Herndon (ORL) Orlando, FL - International (MCO) Oshkosh, WI (OSH) Ottumwa, IA (OTM) Owensboro, KY (OWB) Oxnard/Ventura, CA (OXR) Paducah, KY (PAH) Page, AZ (PGA) Palm Springs, CA (PSP) Panama City, FL (PFN) Parkersburg, WV/Marietta, OH (PKB) Pasco, WA (PSC) Pedro Bay, AK (PDB) Pelican, AK (PEC) Pellston, MI (PLN) Pendleton, OR (PDT) Pensacola, FL (PNS) Peoria, IL (PIA) Perryville, AK (KPV) Petersburg, AK (PSG) Philadelphia, PA - International (PHL) Philadelphia, PA - Trenton/Mercer NJ (TTN) Phoenix, AZ (PHX) Pierre, SD (PIR) Pilot Point, AK - Ugashnik Bay (UGB) Pilot Point, AK (PIP) Pilot Station, AK (PQS) Pittsburgh, PA (PIT) Platinum, AK (PTU) Plattsburgh, NY (PLB) Pocatello, ID (PIH) Point Baker, AK (KPB) Point Hope, AK (PHO) Point Lay, AK (PIZ) Ponca City, OK (PNC) Ponce, Puerto Rico (PSE) Port Alsworth, AK (PTA) Port Angeles, WA (CLM) Port Arthur/Beaumont, TX (BPT) Port Clarence, AK (KPC) Port Heiden, AK (PTH) Port Moller, AK (PML) Port Protection, AK (PPV) Portage Creek, AK (PCA) Portland, ME (PWM) Portland, OR (PDX) Portsmouth, NH (PSM) Poughkeepsie, NY (POU) Prescott, AZ (PRC) Presque Isle, ME (PQI) Princeton, WV (BLF) Providence, RI (PVD) Provincetown, MA (PVC) Prudhoe Bay/Deadhorse, AK (SCC) Pueblo, CO (PUB) Pullman, WA (PUW) Quincy, IL (UIN) Quinhagak, AK (KWN) Raleigh/Durham, NC (RDU) Rampart, AK (RMP) Rapid City, SD (RAP) Reading, PA (RDG) Red Devil, AK (RDV) Redding, CA (RDD) Redmond, OR (RDM) Reno, NV (RNO) Rhinelander, WI, (RHI) Richmond, VA (RIC) Riverton, WY (RIW) Roanoke, VA (ROA) Roche Harbor, WA (RCE) Rochester, MN (RST) Rochester, NY (ROC) Rock Springs, WY (RKS) Rockford, IL (RFD) Rockland, ME (RKD) Rosario, WA (RSJ) Roswell, NM (ROW) Ruby, AK (RBY) Russian Mission, AK (RSH) Rutland, VT (RUT) Sacramento, CA (SMF) Saginaw, MI (MBS) Saint Cloud, MN (STC) Saint George Island, AK (STG) Saint George, UT (SGU) Saint Louis, MO (STL) Saint Mary's, AK (KSM) Saint Michael, AK (SMK) Saint Paul Island, AK (SNP) Salem, OR (SLE) Salina, KS (SLN) Salisbury-Ocean City, MD (SBY) Salt Lake City, UT (SLC) San Angelo, TX (SJT) San Antonio, TX (SAT) San Diego, CA (SAN) San Francisco, CA (SFO) San Jose, CA (SJC) San Juan, Puerto Rico (SJU) San Luis Obispo, CA (SBP) Sand Point, AK (SDP) Sanford, FL (SFB) Santa Ana, CA (SNA) Santa Barbara, CA (SBA) Santa Fe, NM (SAF) Santa Maria, CA (SMX) Santa Rosa, CA (STS) Saranac Lake, NY (SLK) Sarasota, FL (SRQ) Sault Ste Marie, MI, (CIU) Savannah, GA (SAV) Savoonga, AK (SVA) Scammon Bay, AK (SCM) Scottsbluff, NE (BFF) Scranton, PA (AVP) Seattle, WA - Lake Union SPB (LKE) Seattle, WA - Seattle/Tacoma International (SEA) Selawik, AK (WLK) Seward, AK (SWD) Shageluk, AK (SHX) Shaktoolik, AK (SKK) Sheffield/Florence/Muscle Shoals, AL (MSL) Sheldon Point, AK (SXP) Sheridan, WY (SHR) Shishmaref, AK (SHH) Shreveport, LA (SHV) Shungnak, AK (SHG) Silver City, NM (SVC) Sioux City, IA (SUX) Sioux Falls, SD (FSD) Sitka, AK (SIT) Skagway, AK (SGY) Sleetmore, AK (SLQ) South Bend, IN (SBN) South Naknek, AK (WSN) Southern Pines, NC (SOP) Spartanburg/Greenville, SC (GSP) Spokane, WA (GEG) Springfield, IL (SPI) Springfield, MO (SGF) St Petersburg/Clearwater, FL (PIE) State College/University Park, PA (SCE) Staunton, VA (SHD) Steamboat Springs, CO (SBS) Stebbins, AK (WBB) Stevens Point/Wausau, WI (CWA) Stevens Village, AK (SVS) Stewart Field/Newburgh, NY (SWF) Stockton, CA (SCK) Stony River, AK (SRV) Sun Valley, ID (SUN) Syracuse, NY (SYR) Takotna, AK (TCT) Talkeetna, AK (TKA) Tallahassee, FL (TLH) Tampa, FL (TPA) Tanana, AK (TAL) Taos, NM (TSM) Tatitlek, AK (TEK) Teller Mission, AK (KTS) Telluride, CO (TEX) Tenakee Springs, AK (TKE) Terre Haute, IN (HUF) Tetlin, AK (TEH) Texarkana, AR (TXK) Thief River Falls, MN (TVF) Thorne Bay, AK (KTB) Tin City, AK (TNC) Togiak Village, AK (TOG) Tok, AK (TKJ) Toksook Bay, AK (OOK) Toledo, OH (TOL) Topeka, KS (FOE) Traverse City, MI (TVC) Trenton/Mercer, NJ (TTN) Tucson, AZ (TUS) Tulsa, OK (TUL) Tuluksak, AK (TLT) Tuntutuliak, AK (WTL) Tununak, AK (TNK) Tupelo, MS (TUP) Tuscaloosa, AL (TCL) Twin Falls, ID (TWF) Twin Hills, AK (TWA) Tyler, TX (TYR) Unalakleet, AK (UNK) Urbana/Champaign, IL (CMI) Utica, NY (UCA) Utopia Creek, AK (UTO) Vail, CO - Eagle County Airport (EGE) Vail, CO - Van service (QBF) Valdez, AK (VDZ) Valdosta, GA (VLD) Valparaiso, FL (VPS) Venetie, AK (VEE) Ventura/Oxnard, CA (OXR) Vernal, UT (VEL) Victoria, TX (VCT) Visalia, CA (VIS) Waco, TX (ACT) Wainwright, AK (AIN) Wales, AK (WAA) Walla Walla, WA (ALW) Washington DC - All airports (WAS) Washington DC - Dulles (IAD) Washington DC - National (DCA) Waterfall, AK (KWF) Waterloo, IA (ALO) Watertown, NY (ART) Watertown, SD (ATY) Wausau/Stevens Point, WI (CWA) Wenatchee, WA (EAT) West Palm Beach, FL (PBI) West Yellowstone, MT (WYS) Westchester County, NY (HPN) Westerly, RI (WST) Westsound, WA (WSX) Whale Pass, AK (WWP) White Mountain, AK (WMO) White River, VT (LEB) Wichita Falls, TX (SPS) Wichita, KS (ICT) Wilkes Barre, PA (AVP) Williamsburg, VA (PHF) Williamsport, PA (IPT) Williston, ND (ISN) Wilmington, NC (ILM) Windsor Locks, CT (BDL) Worcester, MA (ORH) Worland, WY (WRL) Wrangell, AK (WRG) Yakima, WA (YKM) Yakutat, AK (YAK) Yellowstone/Cody, WY (COD) Youngstown, OH (YNG) Yuma, AZ (YUM)
January 21, 2010
by Snippets Manager
· 4,402 Views
article thumbnail
GWT Development with IntelliJ IDEA Community Edition
I'll use IntelliJ IDEA Community Edition and GWT 2.0.
January 21, 2010
by Victor Tsoukanov
· 45,493 Views
article thumbnail
Struts 2 Tutorial: Struts 2 Ajax Tutorial with Example
Welcome to the last part of 7 article series of Struts 2 Framework tutorials. In we saw how to implement File Upload functionality in Struts 2. In this article we will see how we can implement Ajax support in a webapplication using Struts2 framework. Struts 2 Tutorial List Part 7: Struts 2 Ajax Tutorial with Example AJAX support in Struts 2 Struts 2 provides built-in support to AJAX using Dojo Toolkit library. If you are new to Dojo, you may want to go through the Introduction of DOJO Toolkit. Struts 2 comes with powerful set of Dojo AJAX APIs which you can use to add Ajax support. In order to add Ajax support, you need to add following JAR file in your classpath: struts2-dojo-plugin.jar Also once we add this JAR file, we need to add following code snippet in whatever JSP file we need to add AJAX support. First define the taglib sx which we will use to add AJAX enabled tags. Add this head tag in your JSP between … tags. This sx:head tag will include required javascript and css files to implement Ajax. AJAX Example: Struts2 Ajax Drop Down Let us add simple AJAX support in our StrutsHelloWorld web application. We will use the base code that we used in previous articles and add Ajax on top of it. We will create a drop down which will Autocomplete and suggest the input. For this we will add Dojo support to our webapp. Step 1: Adding JAR file As discussed earlier we will add struts2-dojo-plugin.jar in classpath (WEB-INF/lib). Thus, following is the list of required jar files. Note that these jars are needed to run full application including all the samples of previous parts of this tutorial series. Step 2: Create AJAX Action class We will create an action class which will get called for our Ajax example. Create a file AjaxAutocomplete.java in net.viralpatel.struts2 package and copy following content into it. AjaxAutocomplete.java package net.viralpatel.struts2; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import com.opensymphony.xwork2.ActionSupport; public class AjaxAutocomplete extends ActionSupport { private String data = "Afghanistan, Zimbabwe, India, United States, Germany, China"; private List countries; private String country; public String execute() { countries = new ArrayList(); StringTokenizer st = new StringTokenizer(data, ","); while (st.hasMoreTokens()) { countries.add(st.nextToken().trim()); } return SUCCESS; } public String getCountry() { return this.country; } public List getCountries() { return countries; } public void setCountries(List countries) { this.countries = countries; } public void setCountry(String country) { this.country = country; } } In above code we have created a simple action class with attribute String country and List countries. The countries list will be populated with country names when execute() method is called. Here for this example, we have loaded static data. You may feel free to change this and add data from database. Step 3: Create JSP Create JSP file to display Autocomplete textbox for our Ajax action. Create AjaxDemo.jsp in WebContent directory. AjaxDemo.jsp Struts 2 Autocomplete (Drop down) Example! Country: In above JSP file we have used sx:autocompleter tag to render an autocomplete drop down which users Ajax class to fetch data internally. Note that we have mapped the list attribute with List countries. Step 4: Creating Struts.xml entry Add following action entry in Struts.xml file: /ajaxdemo.tiles /ajaxdemo.tiles Notice that we are using Tiles here in this example. You may want to use AjaxDemo.jsp instead of /ajaxdemo.tiles to render the output directly in JSP. That’s All Folks Compile and Run the application in eclipse. Download Source Code Click here to download Source Code without JAR files (24KB) Conclusion Struts2 Framework provides wide variety of features to create a rich web application. In this Struts2 series we saw different aspects of Struts 2 like introduction of struts2, hello world application, validation framework, tiles plugin, strurts2 interceptors, file upload and ajax support.
January 20, 2010
by Viral Patel
· 124,867 Views
article thumbnail
Struts 2 Tutorial: Create Struts 2 Application in Eclipse
Welcome to the Part 2 of 7-part series where we will explore the world of Struts 2 Framework. In we went through the basics of Struts2, its Architecture diagram, the request processing lifecycle and a brief comparison of Struts1 and Struts2. If you have not gone through the previous article, I highly recommend you to do that before starting hands-on today. Struts 2 Tutorial List Part 7: Struts 2 Ajax Tutorial with Example Related: Create Struts Application with Eclipse Things We Need Before we starts with our first Hello World Struts 2 Example, we will need few tools. JDK 1.5 above (download) Tomcat 5.x above or any other container (Glassfish, JBoss, Websphere, Weblogic etc) (download) Eclipse 3.2.x above (download) Apache Struts2 JAR files:(download). Following are the list of JAR files required for this application. commons-logging-1.0.4.jar freemarker-2.3.8.jar ognl-2.6.11.jar struts2-core-2.0.12.jar xwork-2.0.6.jar Note that depending on the current version of Struts2, the version number of above jar files may change. Our Goal Our goal is to create a basic Struts2 application with a Login page. User will enter login credential and if authenticated successfully she will be redirected to a Welcome page which will display message ”Howdy, …!“. If user is not authenticated, she will be redirected back to the login page. Getting Started Let us start with our first Struts2 based application. Open Eclipse and goto File -> New -> Project and select Dynamic Web Project in the New Project wizard screen. After selecting Dynamic Web Project, press Next. Write the name of the project. For example StrutsHelloWorld. Once this is done, select the target runtime environment (e.g. Apache Tomcat v6.0). This is to run the project inside Eclipse environment. After this press Finish. Once the project is created, you can see its structure in Project Explorer. Now copy all the required JAR files in WebContent -> WEB-INF -> lib folder. Create this folder if it does not exists. Mapping Struts2 in WEB.xml As discussed in the previous article (Introduction to Struts2), the entry point of Struts2 application will be the Filter define in deployment descriptor (web.xml). Hence we will define an entry of org.apache.struts2.dispatcher.FilterDispatcher class in web.xml. Open web.xml file which is under WEB-INF folder and copy paste following code. Struts2 Applicationstruts2org.apache.struts2.dispatcher.FilterDispatcherstruts2/*Login.jsp The above code in web.xml will map Struts2 filter with url /*. The default url mapping for struts2 application will be /*.action. Also note that we have define Login.jsp as welcome file. The Action Class We will need an Action class that will authenticate our user and holds the value for username and password. For this we will create a package net.viralpatel.struts2 in the source folder. This package will contain the action file. Create a class called LoginAction in net.viralpatel.struts2 package with following content. package net.viralpatel.struts2;public class LoginAction {private String username;private String password;public String execute() {if (this.username.equals("admin")&& this.password.equals("admin123")) {return "success";} else {return "error";}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;} Note that, above action class contains two fields, username and password which will hold the values from form and also contains an execute() method that will authenticate the user. In this simple example, we are checking if username is admin and password is admin123. Also note that unlike Action class in Struts1, Struts2 action class is a simple POJO class with required attributes and method. The execute() method returns a String value which will determine the result page. Also, in Struts2 the name of the method is not fixed. In this example we have define method execute(). You may want to define a method authenticate() instead. The ResourceBundle ResourceBundle is very useful Java entity that helps in putting the static content away from the source file. Most of the application define a resource bundle file such as ApplicationResources.properties file which contains static messages such as Username or Password and include this with the application. ResourceBundle comes handy when we want to add Internationalization (I18N) support to an application. We will define an ApplicationResources.properties file for our application. This property file should be present in WEB-INF/classes folders when the source is compiled. Thus we will create a source folder called resources and put the ApplicationResources.properties file in it. To create a source folder, right click on your project in Project Explorer and select New -> Source Folder. Specify folder name resources and press Finish. Create a file ApplicationResources.properties under resources folder. Copy following content in ApplicationResources.properties. label.username= Usernamelabel.password= Passwordlabel.login= Login The JSP We will create two JSP files to render the output to user. Login.jsp will be the starting point of our application which will contain a simple login form with username and password. On successful authentication, user will be redirected to Welcome.jsp which will display a simple welcome message. Create two JSP files Login.jsp and Welcome.jsp in WebContent folder of your project. Copy following content into it. Login.jsp Struts 2 - Login Application Welcome.jsp Howdy, ...! Note that we have used struts2 tag to render the textboxes and labels. Struts2 comes with a powerful built-in tag library to render UI elements more efficiently. The struts.xml file Struts2 reads the configuration and class definition from an xml file called struts.xml. This file is loaded from the classpath of the project. We will define struts.xml file in the resources folder. Create file struts.xml in resources folder. Copy following content into struts.xml. Welcome.jspLogin.jsp Note that in above configuration file, we have defined Login action of our application. Two result paths are mapped with LoginAction depending on the outcome of execute() method. If execute() method returns success, user will be redirected to Welcome.jsp else to Login.jsp. Also note that a constant is specified with name struts.custom.i18n.resources. This constant specify the resource bundle file that we created in above steps. We just have to specify name of resource bundle file without extension (ApplicationResources without .properties). Our LoginAction contains the method execute() which is the default method getting called by Sturts2. If the name of method is different, e.g. authenticate(); then we should specify the method name in tag. Almost Done We are almost done with the application. You may want to run the application now and see the result yourself. I assume you have already configured Tomcat in eclipse. All you need to do: Open Server view from Windows -> Show View -> Server. Right click in this view and select New -> Server and add your server details. To run the project, right click on Project name from Project Explorer and select Run as -> Run on Server (Shortcut: Alt+Shift+X, R) But there is one small problem. Our application runs perfectly fine at this point. But when user enters wrong credential, she is redirected to Login page. But no error message is displayed. User does not know what just happened. A good application always show proper error messages to user. So we must display an error message Invalid Username/Password. Please try again when user authentication is failed. Final Touch To add this functionality first we will add the error message in our ResourceBundle file. Open ApplicationResources.properties and add an entry for error.login in it. The final ApplicationResources.properties will look like: label.username= Usernamelabel.password= Passwordlabel.login= Loginerror.login= Invalid Username/Password. Please try again. Also we need to add logic in LoginAction to add error message if user is not authenticated. But there is one problem. Our error message is specified in ApplicationResources.properties file. We must specify key error.login in LoginAction and the message should be displayed on JSP page. For this we must implement com.opensymphony.xwork2.TextProvider interface which provides method getText(). This method returns String value from resource bundle file. We just have to pass the key value as argument to getText() method. The TextProvider interface defines several method that we must implement in order to get hold on getText() method. But we don’t want to spoil our code by adding all those methods which we do not intend to use. There is a good way of dealing with this problem. Struts2 comes with a very useful class com.opensymphony.xwork2.ActionSupport. We just have to extend our LoginAction class with this class and directly use methods such as getText(), addActionErrors() etc. Thus we will extend the LoginAction class with ActionSupport class and add the logic for error reporting into it. The final code in LoginAction must look like: package net.viralpatel.struts2;import com.opensymphony.xwork2.ActionSupport;public class LoginAction extends ActionSupport {private String username;private String password;public String execute() {if (this.username.equals("admin")&& this.password.equals("admin123")) {return "success";} else {addActionError(getText("error.login"));return "error";}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;} And that’s it. Our first Hello World Struts2 Application is now ready. That’s All Folks Execute the application in Eclipse and run it in your favorite browser. Login page Welcome page Login page with error Download Source Code Click here to download Source Code without JAR files (9KB). Moving On Now that we have created our first webapp using Struts2 framework, we know how the request flows in Struts2. We also know the use of struts.xml and properties file. In this application we implemented a preliminary form of validation. In we will learn more about Validation Framework in Struts2 and implement it in our example. Original article: http://viralpatel.net/blogs/2009/12/tutorial-create-struts-2-application-eclipse-example.html
January 15, 2010
by Viral Patel
· 289,842 Views
article thumbnail
How to Create a Scheduler Module in a Java EE 6 Application with TimerService
Many a time, in a Java EE application, besides the user-triggered transactions via the UI (e.g. from the JSF), there's a need for a mechanism to execute long running jobs triggered over time, e.g., batch jobs. Although in the EJB specs there's a Timer service, where Session Beans can be scheduled to run at intervals through annotations as well as programmatically, the schedule and intervals to execute the jobs have to be pre-determined during development time and Glassfish does not provide the framework and the means to do that out-of-the-box. So it is left to the developer to code that functionality or to choose a 3rd party product to do that. In one of my previous projects using a different application server, I implemented a scheduler module for the application. So with that experience, I will discuss in this article how to create a simple scheduler called SchedulerApp in NetBeans IDE 6.8 that can be deployed in Glassfish v3. The example comes with a framework and the JSF2 PrimeFaces-based UI to schedule and manage (CRUD) your batch jobs implemented by Stateless Session Beans without having to pre-determine the time and interval to execute them during development time. Below is the Class Diagram to give you an overview of the application: Through this exercise, I also hope that you will have a better understanding of the Timer Service in the EJB specs and how you can use it in your projects. Note: If you cannot get your copy running, not to worry, you can get a working copy here. Tutorial Requirements Before we proceed, make sure you review the requirements in this section. Prerequisites This tutorial assumes that you have some basic knowledge of, or programming experience with, the following technologies. JavaServer Faces (JSF) with Facelets Enterprise Java Beans (EJB) 3/3.1 esp. the Timer Service Basic knowledge of using NetBeans IDE will help to reduce the time required to do this tutorial Software needed for this Tutorial Before you begin, you need to download and install the following software on your computer: NetBeans IDE 6.8 (Java pack), http://www.netbeans.org Glassfish Enterprise Server v3, https://glassfish.dev.java.net PrimeFaces Component Library, http://www.primefaces.org Notes: The Glassfish Enterprise Server is included in the Java pack of NetBeans IDE, however, Glassfish can be installed separately from the IDE and added later into Servers services in the IDE. A copy of the working solution is included here if needed. Creating the Enterprise Projects The approach for developing the demo app, SchedulerApp, will be from the back end, i.e., the artifacts and services needed by the front-end UI will be created first, then working forward to the User Interface, i.e., the Ajax-based Web UI will be done last. The first step in creating the application is to create the necessary projects in NetBeans IDE. Choose "File > New Project" to open the New Project Wizard. Under Categories, select Java EE; under Projects select Enterprise Application. Click Next. Select the project location and name the project, SchedulerApp, and click Next. Select the installed Glassfish v3 as the server, and Java EE 6 as the Java EE Version, and click Finish. The above steps will create 3 projects, namely SchedulerApp (Enterprise Application project), SchedulerApp-ejb (EJB project), and SchedulerApp-war (Web project). Creating the Session Beans Before creating the necessary session bean classes, let's look at one of the main classes, JobInfo, which will be heavily used in the application both at the front-end and back. Basically this is a Value Object class that stores information required to configure the timer. Below is an abstract of the class: package com.schedulerapp.common; public class JobInfo implements java.io.Serializable { private static SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); private static SimpleDateFormat sdf2 = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); private String jobId; private String jobName; private String jobClassName; private String description; //Details required by the SchedulerExpression private Date startDate; private Date endDate; private String second; private String minute; private String hour; private String dayOfWeek; private String dayOfMonth; private String month; private String year; private Date nextTimeout; public JobInfo() { this("", "", "java:module/"); } public JobInfo(String jobId, String jobName, String jobClassName) { this.jobId = jobId; this.jobName = jobName; this.jobClassName = jobClassName; this.description = ""; //Default values, everyday midnight this.startDate = new Date(); this.endDate = null; this.second = "0"; this.minute = "0"; this.hour = "0"; this.dayOfMonth = "*"; //Every Day this.month = "*"; //Every Month this.year = "*"; //Every Year this.dayOfWeek = "*"; //Every Day of Week (Sun-Sat) } //Getter and Setter methods for the above attributes... /* * Expression of the schedule set in the object */ public String getExpression() { return "sec=" + second + ";min=" + minute + ";hour=" + hour + ";dayOfMonth=" + dayOfMonth + ";month=" + month + ";year=" + year + ";dayOfWeek=" + dayOfWeek; } @Override public boolean equals(Object anotherObj) { if (anotherObj instanceof JobInfo) { return jobId.equals(((JobInfo) anotherObj).jobId); } return false; } @Override public String toString() { return jobId + "-" + jobName + "-" + jobClassName; } } Notice the class holds the information about the job and its schedule. Create the above class in the EJB project, SchedulerApp-ejb with the package name, com.schedulerapp.common. After creating this class, we are ready to create the session beans. Creating the BatchJob Session Beans In this demo, we will be creating THREE batch jobs, namely: BatchJobA, BatchJobB and BatchJobC, where each is a Stateless Session Bean that implements a Local Interface, BatchJobInterface. The Interface will have a method, executeJob(javax.ejb.Timer timer), so each of the batch job session bean will need to implement it and this becomes the starting point for the batch jobs. Let's proceed to create them and you will see what I mean. In the Projects window, right-click on the SchedulerApp-ejb project and select "New > Session Bean..." In the New Session Bean dialog, specify the EJB Name as BatchJobA, the package as "com.schedulerapp.batchjob", Session Type as Stateless and select Local for Create Interface option Notice 2 files are created: BatchJobA (Implementation class) and BatchJobALocal (Local Interface). Here I want to rename the Interface so that it has a generic name like BatchJobInterface In the project view, navigate to the BatchJobALocal file. Right-click on the item and select "Refactor > Rename...", and change the name to BatchJobInterface. Open the renamed file, BatchJobInterface in the editor, and add the method: @Local public interface BatchJobInterface { public void executeJob(javax.ejb.Timer timer); } Notice the file, BatchJobA becomes errorneous after the above is performed. Open the file, BatchJobA and you should see the error hint (lightbulb with exclamation icon) on the left side of the editor. Click on the icon and select "Implement all abstract methods" and edit the file so that it looks like this: @Stateless public class BatchJobA implements BatchJobInterface { static Logger logger = Logger.getLogger("BatchJobA"); @Asynchronous public void executeJob(Timer timer) { logger.info("Start of BatchJobA at " + new Date() + "..."); JobInfo jobInfo = (JobInfo) timer.getInfo(); try { logger.info("Running job: " + jobInfo); Thread.sleep(30000); //Sleep for 30 seconds } catch (InterruptedException ex) { } logger.info("End of BatchJobA at " + new Date()); } } As you can see, the executeJob method does nothing but just sleeps for 30 sec to simulate a long running job. And because of that, it is made an asynchronous method thru the @Asynchronous annotation so that it doesn't block the calling Session Bean. Notice also that the JobInfo object is extracted from the Timer object so that you have the information to execute your job. We will see later how the JobInfo object got into the Timer object. We will next create the other 2 batch job session beans: BatchJobA and BatchJobB using the Copy/Paste and Refactor features of NB6.8. In the project view, navigate to the file, BatchJobA. Right-click on the item and select "Copy" In the same view, right-click the package, "com.schedulerapp.batchjob" and select "Paste > Refactor Copy..." In the Copy Class dialog, enter "BatchJobB" for the New Name field and click on the Refactor button. Notice the new Session Bean, BatchJobB is created with a few easy clicks of a button. The only thing to change in the new class is the print statements, where "BatchJobA" will be changed to "BatchJobB". Repeat the above steps to create BatchJobC session bean. So we now have THREE batch job session beans: BatchJobA, BatchJobB and BatchJobC that implements the Local Interface, BatchJobInterface. We will next create the last Session Bean for this project. Creating the Job Session Bean Here, we will create the Job Session Bean whose main responsibility is to provide the necessary services to the front-end UI to manage (CRUD) the jobs and also provide the timeout method for the TimerService. In the Projects window, right-click on the SchedulerApp-ejb project and select "New > Session Bean..." In the New Session Bean dialog, specify the EJB Name as JobSessionBean, the package as "com.schedulerapp.ejb", Session Type as Stateless and leave Create Interface unchecked, i.e. no Interface (New in EJB 3.1), and click Finish. Open the newly created file, JobSessionBean in the editor and edit the content so that it looks like the following: @Stateless @LocalBean public class JobSessionBean { @Resource TimerService timerService; //Resource Injection static Logger logger = Logger.getLogger("JobSessionBean"); /* * Callback method for the timers. Calls the corresponding Batch Job Session Bean based on the JobInfo * bounded to the timer */ @Timeout public void timeout(Timer timer) { System.out.println("###Timer <" + timer.getInfo() + "> timeout at " + new Date()); try { JobInfo jobInfo = (JobInfo) timer.getInfo(); BatchJobInterface batchJob = (BatchJobInterface) InitialContext.doLookup( jobInfo.getJobClassName()); batchJob.executeJob(timer); //Asynchronous method } catch (NamingException ex) { logger.log(Level.SEVERE, null, ex); } catch (Exception ex1) { logger.severe("Exception caught: " + ex1); } } /* * Returns the Timer object based on the given JobInfo */ private Timer getTimer(JobInfo jobInfo) { Collection timers = timerService.getTimers(); for (Timer t : timers) { if (jobInfo.equals((JobInfo) t.getInfo())) { return t; } } return null; } /* * Creates a timer based on the information in the JobInfo */ public JobInfo createJob(JobInfo jobInfo) throws Exception { //Check for duplicates if (getTimer(jobInfo) != null) { throw new DuplicateKeyException("Job with the ID already exist!"); } TimerConfig timerAConf = new TimerConfig(jobInfo, true); ScheduleExpression schedExp = new ScheduleExpression(); schedExp.start(jobInfo.getStartDate()); schedExp.end(jobInfo.getEndDate()); schedExp.second(jobInfo.getSecond()); schedExp.minute(jobInfo.getMinute()); schedExp.hour(jobInfo.getHour()); schedExp.dayOfMonth(jobInfo.getDayOfMonth()); schedExp.month(jobInfo.getMonth()); schedExp.year(jobInfo.getYear()); schedExp.dayOfWeek(jobInfo.getDayOfWeek()); logger.info("### Scheduler expr: " + schedExp.toString()); Timer newTimer = timerService.createCalendarTimer(schedExp, timerAConf); logger.info("New timer created: " + newTimer.getInfo()); jobInfo.setNextTimeout(newTimer.getNextTimeout()); return jobInfo; } /* * Returns a list of JobInfo for the active timers */ public List getJobList() { logger.info("getJobList() called!!!"); ArrayList jobList = new ArrayList(); Collection timers = timerService.getTimers(); for (Timer t : timers) { JobInfo jobInfo = (JobInfo) t.getInfo(); jobInfo.setNextTimeout(t.getNextTimeout()); jobList.add(jobInfo); } return jobList; } /* * Returns the updated JobInfo from the timer */ public JobInfo getJobInfo(JobInfo jobInfo) { Timer t = getTimer(jobInfo); if (t != null) { JobInfo j = (JobInfo) t.getInfo(); j.setNextTimeout(t.getNextTimeout()); return j; } return null; } /* * Updates a timer with the given JobInfo */ public JobInfo updateJob(JobInfo jobInfo) throws Exception { Timer t = getTimer(jobInfo); if (t != null) { logger.info("Removing timer: " + t.getInfo()); t.cancel(); return createJob(jobInfo); } return null; } /* * Remove a timer with the given JobInfo */ public void deleteJob(JobInfo jobInfo) { Timer t = getTimer(jobInfo); if (t != null) { t.cancel(); } } } Take note of the followings in the above code: Timer Service is made available thru Resource Injection near the top of the class The callback method for the timers created is timeout thru the use of the @Timeout annotation Notice how the JobInfo object gets into the timer thru the TimerConfig object in the createJob method Notice how the Batch Job session beans are being lookup and accessed in the timeout method. The job class name will be the Portable JNDI name provided by the user in the UI later At this point, we are done with the EJB project, and will now move on to the Web project. Creating the Web UI using JSF 2.0 with PrimeFaces At the time of writing this tutorial, there are not many choices of Ajax-based frameworks that works with JSF 2.0 as it is still quite new. But I have found PrimeFaces to be the most complete and suitable for this demo as it has implemented the dataTable UI component and it seems to be the easiest to integrate into the NetBeans IDE. Preparing the Web project to use JSF 2.0 and PrimeFaces Before creating the web pages, ensure the JavaServer Faces framework is added to the Web project, SchedulerApp-war. In the Project view, right-click on the Web project, SchedulerApp-war, and select Properties (last item). Under the Categories items, select Frameworks, and ensure the JavaServer Faces is added to the Used Frameworks list: Before we are able to use PrimeFaces components in our facelets, we need to include its library in NetBeans IDE and set up a few things. Download the PrimeFaces library (primefaces-2.0.0.RC.jar) from http://www.primefaces.org/downloads.html [13] and store it somewhere on the local disk. To allow future projects to use PrimeFaces, I chose to create a Global library in NetBeans for PrimeFaces. Select "Tools > Libraries" from the NetBeans IDE main menu. In the Library Manager dialog, choose "New Library" and provide a name for the library, e.g. "PrimeFaces2". With the new "PrimeFaces2" library selected, click on the "Add JAR/Folder..." button and select the jar file that was downloaded earlier and click OK to complete: Next, we need to add the newly created library, PrimeFaces2 to the Web project: Select the Web project, SchedulerApp-war, from the Project window, right-click and select "Properties". Under the Libraries category, click on the "Add Library..." button (on the right), and choose the PrimeFaces2 library and click OK to complete: Because we will be using Facelets in our demo, we will update the XHTML template in NetBeans so that all the XHTML files created subsequently will already have the required namespaces and resources needed for the development. Choose "Tools > Templates" from the NetBeans menu. In the Template Manager dialog, select "Web > XHTML" and click the "Open in Editor" button. Edit the content of the file so that it looks like this: <#assign licenseFirst = ""> <#include "../Licenses/license-${project.license}.txt"> TODO write content Lastly, we need to add the following statements in the web.xml file of the Web project for the PrimeFaces components to work properly: Faces Servlet /faces/* *.jsf Resource Servlet org.primefaces.resource.ResourceServlet Resource Servlet /primefaces_resource/* com.sun.faces.allowTextChildren true At this point, we are done setting up and configuring the environment for PrimeFaces to work in NetBeans. In the sections below, we will create the JSF pages to present the screens to perform the CRUD functions. To achieve this, we will be creating THREE web pages: JobList - listing of all the active Jobs/Timers created in a tabular form JobDetails - view/update/delete the selected Job JobNew - create a new Job Creating the Backing Beans for the JSF pages Before creating the actual JSF pages, we first need to create the backing beans that provides the properties and action handlers for the JSF pages (XHTML). Here we will create TWO backing beans: JobList - RequestScoped backing bean for the Job Listing page JobMBean - SessionScoped backing bean for the rest of the JSF pages Steps to create the beans: In the Project view, right-click on the Web project, SchedulerApp-war, and select "New > JSF Managed Bean...", specify JobList as the Class Name, "com.schedulerapp.web" as the Package Name, and the scope to be request Repeat the steps to create the second backing bean, name it JobMBean and set the scope to be session instead. Edit the class, JobList, so that it looks like this: @ManagedBean(name = "JobList") @RequestScoped public class JobList implements java.io.Serializable { @EJB private JobSessionBean jobSessionBean; private List jobList = null; /** Creates a new instance of JobList */ public JobList() { } @PostConstruct public void initialize() { jobList = jobSessionBean.getJobList(); } /* * Returns a list of active Jobs/Timers */ public List getJobs() { return jobList; } } Edit the class, JobMBean, so that it looks like this: @ManagedBean(name = "JobMBean") @SessionScoped public class JobMBean implements java.io.Serializable { @EJB private JobSessionBean jobSessionBean; private JobInfo selectedJob; private JobInfo newJob; /** Creates a new instance of JobMBean */ public JobMBean() { } /* * Getter method for the newJob property */ public JobInfo getNewJob() { return newJob; } /* * Setter method for the newJob property */ public void setNewJob(JobInfo newJob) { this.newJob = newJob; } /* * Getter method for the selectedJob property */ public JobInfo getSelectedJob() { return selectedJob; } /* * Setter method for the selectedJob property */ public String setSelectedJob(JobInfo selectedJob) { this.selectedJob = jobSessionBean.getJobInfo(selectedJob); return "JobDetails"; } /* * Action handler for back to Listing Page */ public String gotoListing() { return "JobList"; } /* * Action handler for New Job button */ public String gotoNew() { System.out.println("gotoNew() called!!!"); newJob = new JobInfo(); return "JobNew"; } /* * Action handler for Duplicate button in the Details page */ public String duplicateJob() { newJob = selectedJob; newJob.setJobId(""); return "JobNew"; } /* * Action handler for Update button in the Details page */ public String updateJob() { FacesContext context = FacesContext.getCurrentInstance(); try { selectedJob = jobSessionBean.updateJob(selectedJob); context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Success", "Job successfully updated!")); } catch (Exception ex) { Logger.getLogger(JobMBean.class.getName()).log(Level.SEVERE, null, ex); context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Failed", ex.getCause().getMessage())); } return null; } /* * Action handler for Delete button in the Details page */ public String deleteJob() { jobSessionBean.deleteJob(selectedJob); return "JobList"; } /* * Action handler for Create button in the New page */ public String createJob() { FacesContext context = FacesContext.getCurrentInstance(); try { selectedJob = jobSessionBean.createJob(newJob); context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Sucess", "Job successfully created!")); return "JobDetails"; } catch (Exception ex) { Logger.getLogger(JobMBean.class.getName()).log(Level.SEVERE, null, ex); context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Failed", ex.getCause().getMessage())); } return null; } } Now, we have all the services and properties ready to be used by the JSF pages. Creating the JSF pages Finally, we are ready to create the THREE JSF pages: JobList, JobDetails and JobNew. In the Project view, right-click on the Web project, SchedulerApp-war, and select "New > XHTML...", specify JobList as the File Name. Note: If the item "XHTML..." doesn't appear in your menu list, select "New > Others..." instead, then in the New File dialog, select Web under Categories and you should be able to see the XHTML file type on the right. Repeat the above step for JobDetails and JobNew. Edit the file, JobList.xhtml to look like this: Job List Edit the file, JobDetails.xhtml to look like this: Help Edit the file, JobNew.xhtml to look like this: Help At this point, we are done with all the coding, and it's now time to verify the results. Perform a "Clean and Build" of the project and deploy it to the Glassfish v3 server. Testing the application Here, we will do a simple test to verify that the application is working. We will schedule 3 jobs as follows: Job 1 - run BatchJobA every 2 minutes (just to make sure we see the job running) Job 2 - run BatchJobB everyday at 11pm Job 3 - run BatchJobC every Sunday at 1am Steps to create the jobs: Go to the listing page, http://localhost:8080/SchedulerApp-war/JobList.jsf and you should see the following screen: Click on the "New Job" button below the table. Enter the details for Job 1 as follows and click on the "Create" button Click on the "Duplicate" button below to create a new Job using the current information. Enter the details for Job 2 as follows and click on the "Create" button Click on the "Duplicate" button below to create a new Job using the current information. Enter the details for Job 3 as follows and click on the "Create" button At this point, we are done creating the jobs, click on the "Back" button to see the listing. The Job List page should consists of 3 jobs that was created in the above steps Things to Note The Portable JNDI syntax for accessing the Session Beans: BatchJobA, BatchJobB and BatchJobC The "*" in the text fields represents "Every", see Java EE 6 Tutorial for details You should be able see in the log file, server.log, that BatchJobA now runs every 2 minutes The timers(jobs) are persistent, i.e. they will survive server restarts. Try restarting ther server and view the Job list again Try out the other functions of the CRUD and schedule your own jobs to see it in action. Summary Congratulations! You now have a simple scheduler to schedule your long running jobs in your application. With this framework and the GUI, you can have the flexibility and full control over the jobs you want to manage without having to pre-determine the time and interval to run them during Design and Development phase. Although the timers are persistent, the server may remove them when changes, such as new deployments, are detected. As such, you can further extend the scheduler to persist information in the database in a more dynamic and complex environment, e.g., a cluster. Good luck and have fun using the Scheduler. If you cannot get your copy running, not to worry, you can get a working copy here. See Also For other related resources, see the following: Develop Java EE 5 application with Visual JSF, EJB3 and JPA Securing Java EE 6 application with JEE Security and LDAP How to Create a Java EE 6 Application with JSF 2, EJB 3.1, JPA, and NetBeans IDE 6.8
January 10, 2010
by Christopher Lam
· 109,698 Views · 1 Like
article thumbnail
Groovy AST Transformations by Example: Adding Methods to Classes
What can you do with a Groovy AST Transformation? A difficult question, considering the answer is "almost anything".
January 8, 2010
by Hamlet D'Arcy
· 46,393 Views
article thumbnail
Binaural Beats With Python
How to use python and ALSA to generate binaural beats. # A very simple python example to generate binaural beats. # The data is sent to the device in a too basic way, so the # script only works well with integer frecuencies. from alsaaudio import * from struct import pack from math import sin, pi # Channel 1 frec1=317 #Frecuency vol1=1 #Volume #Channel 2 frec2=323 #Frecuency vol2=1 #Volume #Very basic choice of parameters rate = 44100 period = 44100 channels = 2 # device initialization out = PCM(type=PCM_PLAYBACK, mode=PCM_NORMAL, card='default') # parameters out.setchannels(channels) out.setrate(rate) out.setformat(PCM_FORMAT_S32_LE) out.setperiodsize(period) # a list with the sinusoidal signals is built maxAmp = pow(2,31) - 1 list = [] i=period while(i>0): list.append(maxAmp*vol1*sin(frec1*float(i)/rate*2*pi)) list.append(maxAmp*vol2*sin(frec2*float(i)/rate*2*pi)) i-=1 # and the list is writen over and over again. Just kill the process to stop. s=pack('<'+channels*period*'l',*list) while(1): out.write(s)
January 5, 2010
by Snippets Manager
· 2,916 Views
article thumbnail
Java Content Repository: The Best Of Both Worlds
Learn the basics of Java Content Repositories, including how they work, and how they're used.
January 4, 2010
by Bertrand Delacretaz
· 144,546 Views · 5 Likes
article thumbnail
Spring Integration and Apache Camel
Spring Integration and Apache Camel are open source frameworks providing a simpler solution for the Integration problems in the enterprise, to quote from their respective websites: Apache Camel - Apache Camel is a powerful open source integration framework based on known Enterprise Integration Patterns with powerful Bean Integration. Spring Integration - It provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns while building on the Spring Framework's existing support for enterprise integration. Essentially Spring Integration and Apache Camel enable applications to integrate with other systems. This article seeks to provide an implementation for an integration problem using both Spring Integration and Apache Camel. The objective is to show how easy it is to use these frameworks for a fairly complicated integration problem and to recommend either of these great products for your next Integration challenge. Problem: To illustrate the use of these frameworks consider a simple integration scenario, described using EIP terminology: The application needs to get a "Report" by aggregating "Sections" from a Section XML over http service. Each request for Report consists of a set of request for sections – in this specific example there are requests for three sections, the header, body and footer. The XML over http service returns a Section for the Section Request. The responses need to be aggregated into a single report. A sample test for this scenario is of the following type: ReportGenerator reportGenerator = reportGeneratorFactory.createReportGenerator(); List sectionRequests = new ArrayList(); String entityId="A Company"; sectionRequests.add(new SectionRequest(entityId,"header")); sectionRequests.add(new SectionRequest(entityId,"body")); sectionRequests.add(new SectionRequest(entityId,"footer")); ReportRequest reportRequest = new ReportRequest(sectionRequests); Report report = reportGenerator.generateReport(reportRequest); List sectionOfReport = report.getSections(); System.out.println(report); assertEquals(3, sectionOfReport.size()); The “ReportGenerator” is the messaging gateway, hiding the details of the underlying messaging infrastructure and in this specific case also the integration API – Apache Camel or Spring Integration. To start with, let us implement a solution to this integration problem using Spring Integration as the Framework, followed by Apache Camel. The complete working code using Spring Integration and Apache Camel is also available with the article. Solution Using Spring Integration: The Gateway component is easily configured using the following entry in the Spring Configuration. Internally Spring Integration uses AOP to hook up a component which routes the requests from an internal input channel and waits for the response in the response channel. The component to Split the Input Report Request to Section Request is fairly straightforward: public class SectionRequestSplitter { public List split(ReportRequest reportRequest){ return reportRequest.getSectionRequests(); } } and to hook this splitter with Spring Integration: Next, to transform the Section Request to an XML format - The component is the following: public class SectionRequestToXMLTransformer { public String transform(SectionRequest sectionRequest){ //this needs to be optimized...purely for demonstration of the concept String sectionRequestAsString = "" + sectionRequest.getEntityId() + "" + sectionRequest.getSectionId() + ""; return sectionRequestAsString; } } and is hooked up in the Spring Integration configuration file in the following way: To send an XML over http request using the Section Request XML to a section Service: To transform the Section Response XML to a Section Object - The component is the following: public class SectionResponseXMLToSectionTransformer { public Section transform(String sectionXML) { SAXReader saxReader = new SAXReader(); Document document; String sectionName = ""; String entityId = ""; try { document = saxReader.read(new StringReader(sectionXML)); sectionName = document .selectSingleNode("/section/meta/sectionName").getText(); entityId = document.selectSingleNode("/section/meta/entityId") .getText(); } catch (DocumentException e) { e.printStackTrace(); } return new Section(entityId, sectionName, sectionXML); } } and is hooked up in the Spring Integration configuration file in the following way: To aggregate the Sections together into a report, the component is the following:: public class SectionResponseAggregator { public Report aggregate(List sections) { return new Report(sections); } } and is hooked up in the Spring Integration configuration file in the following way: This completes the Spring Integration implementation for this Integration Problem. The following is the complete Spring Integration configuration file: A working sample is provided with the article(Download, extract and run "mvn test") Solution using Apache Camel: Apache Camel allows the route to be defined using multiple DSL implementations – Java DSL, Scala DSL and an XML based DSL. The recommended approach is to use Spring CamelContext as a runtime and the Java DSL for route development. The following is to build the Spring Camel Context: The route is configured by the Java based DSL: public class CamelRouteBuilder extends RouteBuilder { private String serviceURL; @Override public void configure() throws Exception { from("direct:start") .split().method("sectionRequestSplitterBean", "split") .aggregationStrategy(new ReportAggregationStrategy()) .transform().method("sectionRequestToXMLBean", "transform") .to(serviceURL) .transform().method("sectionResponseXMLToSectionBean", "transform"); } public void setServiceURL(String serviceURL) { this.serviceURL = serviceURL; } } Apache Camel does not provide an out of the box Message Gateway feature, however it is fairly easy to create a wrapper component that can hide the underlying details in the following way: Reader davsclaus has provided references to two mechanisms with Apache Camel to provide an out of the box Messaging Gateway - Messaging Gateway EIP and Camel Proxy which allows a POJO to be used as a Mesaging Gateway. Camel Proxy will be used with the article, and can be configured in the Camel Configuration files in the following way: Per davsclaus, there is a bug in Apache Camel(2.1 or older) when invoking a bean later in the route(the splitter bean), which is to be fixed in Apache Camel 2.2. To work around this bug, a convertBody step will be introduced in the route: from("direct:start") .convertBodyTo(ReportRequest.class) .split(bean("sectionRequestSplitterBean", "split"), new ReportAggregationStrategy()) .transform().method("sectionRequestToXMLBean", "transform") .to(serviceURL) .transform().method("sectionResponseXMLToSectionBean", "transform"); The component to Split the Input Report Request to Section Request is exactly same as Spring Integration component: public class SectionRequestSplitter { public List split(ReportRequest reportRequest){ return reportRequest.getSectionRequests(); } } To hook the component with Apache Camel: from("direct:start") .split().method("sectionRequestSplitterBean", "split") .... Next to transform the Section Request to an XML format, again this is exactly same as the implementation for Spring Integration, with hook being provided in the following manner: ...... .transform().method("sectionRequestToXMLBean", "transform") ...... To send an XML over http request using the Section Request XML to a section Service: ...... .transform().method("sectionRequestToXMLBean", "transform") .to(serviceURL) ......... To transform the Section Response XML to a Section object, the component is exactly same as the one used with Spring Integration, with the following highlighted hook in the Camel route: ...... .transform().method("sectionResponseXMLToSectionBean", "transform"); To aggregate the Section responses together into a report, the component is a bit more complicated than Spring Integration. Apache Camel supports a Scatter/Gather pattern using a route of the following type: ...... .split().method("sectionRequestSplitterBean", "split") .aggregationStrategy(new ReportAggregationStrategy()) with an aggregation strategy being passed on to the Splitter, the aggregation strategy implementation is the following: public class ReportAggregationStrategy implements AggregationStrategy { @Override public Exchange aggregate(Exchange oldExchange, Exchange newExchange) { if (oldExchange == null) { Section section = newExchange.getIn().getBody(Section.class); Report report = new Report(); report.addSection(section); newExchange.getIn().setBody(report); return newExchange; } Report report = oldExchange.getIn().getBody(Report.class); Section section = newExchange.getIn().getBody(Section.class); report.addSection(section); oldExchange.getIn().setBody(report); return oldExchange; } } This completes the Apache Camel based implementation. A working sample for Camel is provided with the article - just download, extract and run "mvn test". Conclusion: Spring Integration and Apache Camel provide a simple and clean approach for the Integration problems in a typical enterprise. They are lightweight frameworks – Spring Integration builds on top of Spring portfolio and extends the familiar programming model for the Integration domain and is easy to pick up, Apache camel provides a good Java based DSL and integrates well with Spring Core, with a fairly gentle learning curve. The article does not recommend one product over the other but encourages the reader to evaluate and learn from both these frameworks. References: Spring Integration Website: http://www.springsource.org/spring-integration Apache Camel Website: http://camel.apache.org/ Spring Integration Reference: http://static.springsource.org/spring-integration/reference/htmlsingle/spring-integration-reference.html Apache Camel User Guide: http://camel.apache.org/user-guide.html Plug for my blog: http://biju-allandsundry.blogspot.com/
December 31, 2009
by Biju Kunjummen
· 102,092 Views · 3 Likes
article thumbnail
How to Create a Java EE 6 Application with JSF 2, EJB 3.1, JPA, and NetBeans IDE 6.8
Develop a web-based app based on technologies in the JEE6 specs such as Enterprise Java Beans 3.1 and JPA with the help of NetBeans IDE 6.8.
December 29, 2009
by Christopher Lam
· 723,251 Views · 3 Likes
article thumbnail
Automated Deployment With Cargo and Maven - a Short Primer
Cargo is a versatile library that lets you manage, and deploy applications to, a variety of application servers. In this article, we look at how to use Cargo with Maven. If you are starting from scratch, you can use an Archetype to create a Cargo-enabled web application: mvn archetype:create -DarchetypeGroupId=org.codehaus.cargo -DarchetypeArtifactId=cargo-archetype-webapp-single-module -DgroupId=com.wakaleo -DartifactId=ezbank Or it is easy to add to an existing configuration - just add the cargo-maven2-plugin to your pom file. The default configuration will deploy the application to an embedded Jetty server: org.codehaus.cargo cargo-maven2-plugin 1.0 Then just run mvn cargo:start. However Cargo is designed for deployment, and does not support rapid lifecycle development - use the ordinary Jetty plugin for that. Deploying to a Tomcat instance You can run your integration tests against a Tomcat server that Cargo will initialize and configure for the occasion - this is referred to as 'standalone' mode: org.codehaus.cargo cargo-maven2-plugin 1.0 tomcat6x /usr/local/apache-tomcat-6.0.18 standalone target/tomcat6x Cargo will create a base directory (think CATALINA_BASE) in a directory that you specify. It will use the Tomcat home directory that you provide. At each installation, Cargo will destroy and recreate the base directory. You can also download and install a Tomcat installation as required using the element: http://www.orionserver.com/distributions/orion2.0.5.zip ${java.io.tmpdir}/cargoinstalls This is a more portable solution which is useful for integration tests Running integration tests with Cargo You can use Cargo to automatically start up a web server to run your integration tests. This means you can run your integration tests on any of the supported servers (Tomcat, Jetty, JBoss, Weblogic,...): org.codehaus.cargo cargo-maven2-plugin 1.0 start-container pre-integration-test start stop-container post-integration-test stop false tomcat6x /usr/local/apache-tomcat-6.0.18 standalone target/tomcat6x Deploying to an existing server You can also deploy to a running application server. You need to use the 'existing' configuration type (existing). You can use a separate profile to run the integration tests in a standalone instance and then deploy to a running instance. integration org.codehaus.cargo cargo-maven2-plugin 1.0 tomcat6x existing /usr/local/apache-tomcat-6.0.18 ... Then you can deploy your application as shown here: $ mvn install $ mvn cargo:deploy -Pintegration Deploying to a remote server You can also deploy to a remote server, using the server-specific remote API (e.g. the HTML manager application for Tomcat). You need to set up a container of type 'remote' and a configuration of type 'runtime': tomcat6x remote runtime admin http://localhost:8888/manager ... In the section, you define server-specific properties (see the Cargo documentation). Then you use Cargo as usual: $ mvn cargo:redeploy -o ... [INFO] [cargo:redeploy] [INFO] [mcat6xRemoteDeployer] Redeploying [/Users/johnsmart/.m2/repository/org/ebank/ ebank-web/1.0.0-SNAPSHOT/ebank-web-1.0.0-SNAPSHOT.war] [INFO] [mcat6xRemoteDeployer] Undeploying [/Users/johnsmart/.m2/repository/org/ebank/ ebank-web/1.0.0-SNAPSHOT/ebank-web-1.0.0-SNAPSHOT.war] [INFO] [mcat6xRemoteDeployer] Deploying [/Users/johnsmart/.m2/repository/org/ebank/ ebank-web/1.0.0-SNAPSHOT/ebank-web-1.0.0-SNAPSHOT.war] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4 seconds [INFO] Finished at: Fri Jul 17 17:45:34 CEST 2009 [INFO] Final Memory: 6M/12M [INFO] ------------------------------------------------------------------------ Using a dedicated deployer module You can dissociate the build process from the application deployment process by creating a separate Maven module dedicated to deployments. This also makes it easier to build and deploy your WAR file to Nexus on one server, and then deploy to your application server directly on the target machine. To do this, you create a dedicated Maven module. It only needs to contain the Cargo plugin and a dependency on the application to be deployed. The Cargo plugin uses the section to obtain the WAR file to be deployed from your Nexus repository. ... org.codehaus.cargo cargo-maven2-plugin 1.0 tomcat6x existing /usr/local/apache-tomcat-6.0.18 ebank-web org.ebank war The dependencies section contains a reference to the WAR file to be deployed. You can use a property here so that you can pass a version number from the command line: ... org.ebank ebank-web war ${target.version} ${project.version} From http://weblogs.java.net/blog/johnsmart
December 29, 2009
by John Ferguson Smart
· 39,278 Views · 1 Like
article thumbnail
JavaScript: Wrap All Methods (functions) In A Class With An Error Handler.
Example of a way to wrap all methods in a class with an error handler. Could stand more improvement. /** @Description: Takes in an exception or string and turns it into an Error object, then appends the caller name to the message. @Returns: A new Error object or null. */ function wrapError (e, caller) { if (null === e) { return null; } var ret = ( (typeof e) === (typeof "") ) ? new Error(e) : new Error(e.message); ret.stackTrace = e.stackTrace || []; ret.stackTrace.push(caller); return ret; } /** @Description: Returns a method (function) wrapped in an error handler. Does not affect the behavior of the underlying function. Does not affec the function either, only returns the wrapped function, doesn't modify it directly. Usage: function foo() { throw new Error("bar"); }; foo = safeWrapMethod(foo, "foo"); @Param: fn The function pointer/object to wrap. @Param: name A string containing the name of fn as you wish it to be displayed in the call stack. @Return: The method/function fn wrapped in an error handler. */ function safeWrapMethod (fn, name) { try { return function () { /* Wrapper added by safeWrapMethod */ try { return fn.apply(this, arguments); } catch (e) { throw wrapError(e, name); } }; } catch (e) { throw wrapError(e, "ErrorHelpers.safeWrapMethod"); } } /** @Description: Wraps every method in an object with an error handler. Affects the instance of the object, but does not alter the underlying behavior of the methods. @Param: o The class instance (object) to wrap. @Param: name A string containing the name of the class. Method names will show as "name.methodName" in an error's stack trace. */ function safeWrapClass (o, name) { for (var m in o) { if (typeof(o[m]) === "function") { o[m] = safeWrapMethod(o[m], name + "." + m); } } }; safeWrapClass = safeWrapMethod(safeWrapClass, "ErrorHelpers.safeWrapClass"); // Example Usage function Foo() { safeWrapClass(this, "Foo"); }; Foo = safeWrapMethod(Foo, "Foo.ctor"); Foo.prototype.a = function () { throw new Error("oh noes!"); }; Foo.prototype.b = function () { this.a(); } Foo.prototype.c = function () { this.b(); } try { var f = new Foo(); f.c(); } catch (e) { var msg = e.message; if (e.stackTrace) { msg += "\r\n\r\nstackTrace: " + e.stackTrace.join("\r\n\tat "); } alert(msg); /* oh noes! stackTrace: Foo.a at Foo.b at Foo.c */ }
December 18, 2009
by Jason McDonald
· 8,369 Views
article thumbnail
Maven Repository Manager: Nexus Vs. Artifactory
My goal is to compare Sonatype Nexus and JFrog Artifactory,the two leading open source Maven repository managers.
December 14, 2009
by Ori Dar
· 136,468 Views · 4 Likes
article thumbnail
How to Create a Swing CRUD Application on NetBeans Platform 6.8
this article shows you how to integrate a java db database into a netbeans platform application. we start by exploring a java db database, from which we create entity classes. next, we wrap the entity classes into a module, together with modules for the related jpa jars. note: these instructions are not applicable to java db only. rather, they are relevant to any relational database, such as oracle or mysql. several applications on the netbeans platform, many of which are listed here , use these databases too. java db was chosen for this article because it is easiest to get started with, since it comes with the jdk. once the above modules are part of our application, we create a new module that provides the user interface for our application. the new module gives the user a tree hierarchy showing data from the database. we then create another module that lets the user edit the data displayed by the first module. by separating the viewer from the editor in distinct modules, we will enable the user to install a different editor for the same viewer, since different editors could be created by external vendors, some commercially and some for free. it is this flexibility that the modular architecture of the netbeans platform makes possible. when we have a module for our editor, we begin adding crud functionality. first, the "r", standing for "read", is handled by the viewer described above. next, the "u" for "update" is handled, followed by the "c" for "create", and the "d" for "delete". at the end of the article, you will have learned about a range of netbeans platform features that help you in creating applications of this kind. for example, you will have learned about the undoredo.manager and the explorermanager , as well as netbeans platform swing components, such as topcomponent and beantreeview . contents setting up the application integrating the database creating entity classes from a database wrapping the entity class jar in a module creating other related modules designing the user interface setting dependencies running the prototype integrating crud functionality read update create delete the application you create in this article will look as follows: source code: http://kenai.com/projects/nbcustomermanager once you're at the stage shown above, you can simply download a netbeans module that provides office laf support ( ), add it to your application, and then when you redeploy the application, you will see this: note: it is advisable to watch the screencast series top 10 netbeans apis before beginning to work on this article. many of the concepts addressed in this article are discussed in more detail within the screencast series. setting up the application let's start by creating a new netbeans platform application. choose file > new project (ctrl+shift+n). under categories, select netbeans modules. under projects, select netbeans platform application. click next. in the name and location panel, type dbmanager in the project name field. click finish. the ide creates the dbmanager project. the project is a container for all the other modules you will create. run the application and notice that you have quite a few features out of the box already. open some of the windows, undock them, and get to know the basic components that the netbeans platform provides without you doing any work whatsoever: integrating the database in order to integrate the database, you need to create entity classes from your database and integrate those entity classes, together with their related jars, into modules that are part of your netbeans platform application. creating the entity classes in this section, you generate entity classes from a selected database. for purposes of this example, use the services window to connect to the sample database that is included with netbeans ide: note: alternatively, use any database you like and adapt the steps that follow to your particular use case. in the case of mysql, see connecting to a mysql database . in the ide, choose file | new project, followed by java | java class library to create a new library project named customerlibrary. in the projects window, right-click the library project and choose file | new file, followed by persistence | entity classes from database. in the wizard, select your database and the tables you need. here we choose "customer", and then "discount code" is added automatically, since there is a relationship between these two tables. specify the persistence strategy, which can be any of the available options. here, since we need to choose something, we'll choose eclipselink: specify "demo" as the name of the package where the entity classes will be generated. click finish. once you have completed this step, look at the generated code and notice that, among other things, you now have a persistence.xml file in a folder called meta-inf, as well as entity classes for each of your tables: build the java library and you will have a jar file in the library project's "dist" folder, which you can view in the files window: wrapping the entity class jar in a module in this section, you add your first module to your application! the new netbeans module will wrap the jar file you created in the previous section. right-click the dbmanager's modules node in the projects window and choose add new library. select the jar you created in the previous subsection and complete the wizard, specifying any values you like. let's assume the application is for dealing with customers at shop.org, in which case a unique identifier "org.shop.model" is appropriate for the code name base: you now have your first custom module in your new application, wrapping the jar containing the entity classes and the persistence.xml file: creating other related modules in this section, you create two new modules, wrapping the eclipselink jars, as well as the database connector jar. do the same as you did when creating the library wrapper for the entity class jar, but this time for the eclipselink jars, which are in the "customerlibrary" java library that you created earlier: note: in the library wrapper module wizard, you can use ctrl-click to select multiple jars. next, create yet another library wrapper module, this time for the java db client jar, which is available in your jdk distribution, at db/lib/derbyclient.jar. designing the user interface in this section, you create a simple prototype user interface, providing a window that uses a jtextarea to display data retrieved from the database. right-click the dbmanager's modules node in the projects window and choose add new. create a new module named customerviewer, with the code name base org.shop.ui. in the projects window, right-click the new module and choose new | window component. specify that it should be created in the editor position and that it should open when the application starts. set customer as the window's class name prefix. use the palette (ctrl-shift-8) to drag and drop a jtextarea on the new window: add this to the end of the topcomponent constructor: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); for (customer c : resultlist) { jtextarea1.append(c.getname() + " (" + c.getcity() + ")" + "\n"); } note: since you have not set dependencies on the modules that provide the customer object and the persistence jars, the statements above will be marked with red error underlines. these will be fixed in the section that follows. above, you can see references to a persistence unit named "customerlibrarypu", which is the name set in the persistence.xml file. in addition,there is a reference to one of the entity classes, called customer, which is in the entity classes module. adapt these bits to your needs, if they are different to the above. setting dependencies in this section, you enable some of the modules to use code from some of the other modules. you do this very explicitly by setting intentional contracts between related modules, i.e., as opposed to the accidental and chaotic reuse of code that tends to happen when you do not have a strict modular architecture such as that provided by the netbeans platform. the entity classes module needs to have dependencies on the derby client module as well as on the eclipselink module. right-click the customerlibrary module, choose properties, and use the libraries tab to set dependencies on the two modules that the customerlibrary module needs. the customerviewer module needs a dependency on the eclipselink module as well as on the entity classes module. right-click the customerviewer module, choose properties, and use the libraries tab to set dependencies on the two modules that the customerviewer module needs. open the customertopcomponent in the source view, right-click in the editor, and choose "fix imports". the ide is now able to add the required import statements, because the modules that provide the required classes are now available to the customertopcomponent. you now have set contracts between the modules in your application, giving you control over the dependencies between distinct pieces of code. running the prototype in this section, you run the application so that you can see that you're correctly accessing your database. start your database server. run the application. you should see this: you now have a simple prototype, consisting of a netbeans platform application that displays data from your database, which you will extend in the next section. integrating crud functionality in order to create crud functionality that integrates smoothly with the netbeans platform, some very specific netbeans platform coding patterns need to be implemented. the sections that follow describe these patterns in detail. read in this section, you change the jtextarea, introduced in the previous section, for a netbeans platform explorer view. netbeans platform explorer views are swing components that integrate better with the netbeans platform than standard swing components do. among other things, they support the notion of a context, which enables them to be context sensitive. representing your data, you will have a generic hierarchical model provided by a netbeans platform node class, which can be displayed by any of the netbeans platform explorer views. this section ends with an explanation of how to synchronize your explorer view with the netbeans platform properties window. in your topcomponent, delete the jtextarea in the design view and comment out its related code in the source view: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); //for (customer c : resultlist) { // jtextarea1.append(c.getname() + " (" + c.getcity() + ")" + "\n"); //} right-click the customerviewer module, choose properties, and use the libraries tab to set dependencies on the nodes api and the explorer & property sheet api. next, change the class signature to implement explorermanager.provider: final class customertopcomponent extends topcomponent implements explorermanager.provider you will need to override getexplorermanager() @override public explorermanager getexplorermanager() { return em; } at the top of the class, declare and initialize the explorermanager: private static explorermanager em = new explorermanager(); note: watch top 10 netbeans apis for details on the above code, especially the screencast dealing with the nodes api and the explorer & property sheet api. switch to the topcomponent design view, right-click in the palette, choose palette manager | add from jar. then browse to the org-openide-explorer.jar, which is in platform11/modules folder, within the netbeans ide installation directory. choose the beantreeview and complete the wizard. you should now see beantreeview in the palette. drag it from the palette and drop it on the window. create a factory class that will create a new beannode for each customer in your database: import demo.customer; import java.beans.introspectionexception; import java.util.list; import org.openide.nodes.beannode; import org.openide.nodes.childfactory; import org.openide.nodes.node; import org.openide.util.exceptions; public class customerchildfactory extends childfactory { private list resultlist; public customerchildfactory(list resultlist) { this.resultlist = resultlist; } @override protected boolean createkeys(list list) { for (customer customer : resultlist) { list.add(customer); } return true; } @override protected node createnodeforkey(customer c) { try { return new beannode(c); } catch (introspectionexception ex) { exceptions.printstacktrace(ex); return null; } } } back in the customertopcomponent, use the explorermanager to pass the result list from the jpa query in to the node: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); em.setrootcontext(new abstractnode(children.create(new customerchildfactory(resultlist), true))); //for (customer c : resultlist) { // jtextarea1.append(c.getname() + " (" + c.getcity() + ")" + "\n"); //} run the application. once the application is running, open the properties window. notice that even though the data is available, displayed in a beantreeview, the beantreeview is not synchronized with the properties window, which is available via window | properties. in other words, nothing is displayed in the properties window when you move up and down the tree hierarchy. synchronize the properties window with the beantreeview by adding the following to the constructor in the topcomponent: associatelookup(explorerutils.createlookup(em, getactionmap())); here we add the topcomponent's actionmap and explorermanager to the lookup of the topcomponent. run the application again and notice that the properties window is now synchronized with the explorer view: now you are able to view your data in a tree hierarchy, as you would be able to do with a jtree. however, you're also able to swap in a different explorer view without needing to change the model at all because the explorermanager mediates between the model and the view. finally, you are now also able to synchronize the view with the properties window. update in this section, you first create an editor. the editor will be provided by a new netbeans module. so, you will first create a new module. then, within that new module, you will create a new topcomponent, containing two jtextfields, for each of the columns you want to let the user edit. you will need to let the viewer module communicate with the editor module. whenever a new node is selected in the viewer module, you will add the current customer object to the lookup. in the editor module, you will listen to the lookup for the introduction of customer objects. whenever a new customer object is introduced into the lookup, you will update the jtextfields in the editor. next, you will synchronize your jtextfields with the netbeans platform's undo, redo, and save functionality. in other words, when the user makes changes to a jtextfield, you want the netbeans platform's existing functionality to become available so that, instead of needing to create new functionality, you'll simply be able to hook into the netbeans platform's support. to this end, you will need to use the undoredomanager, together with the savecookie. create a new module, named customereditor, with org.shop.editor as its code name base. right-click the customereditor module and choose new | window component. make sure to specify that the window should appear in the editor position and that it should open when the application starts. in the final panel of the wizard, set "editor" as the class name prefix. use the palette (ctrl-shift-8) to add two jlabels and two jtextfields to the new window. set the texts of the labels to "name" and "city" and set the variable names of the two jtextfields to jtextfield1 and jtextfield2. in the gui builder, the window should now look something like this: go back to the customerviewer module and change its layer.xml file to specify that the customertopcomponent window will appear in the explorer mode. note: right-click the application project and choose "clean", after changing the layer.xml file. why? because whenever you run the application and close it down, the window positions are stored in the user directory. therefore, if the customerviewer was initially displayed in the editor mode, it will remain in the editor mode, until you do a "clean", thus resetting the user directory (i.e., thus deleting the user directory) and enabling the customerviewer to be displayed in the position currently set in the layer.xml file. also check that the beantreeview in the customerviewer will stretch horizontally and vertically when the user resizes the application. check this by opening the window, selecting the beantreeview, and then clicking the arrow buttons in the toolbar of the gui builder. run the application and make sure that you see the following when the application starts up: now we can start adding some code. firstly, we need to show the currently selected customer object in the editor: start by tweaking the customerviewer module so that the current customer object is added to the viewer window's lookup whenever a new node is selected. do this by creating an abstractnode, instead of a beannode, in the customerchildfactory class. that enables you to add the current customer object to the lookup of the node, as follows (note the "lookups.singleton(c)" below): @override protected node createnodeforkey(customer c) { node node = new abstractnode(children.leaf, lookups.singleton(c)); node.setdisplayname(c.getname()); node.setshortdescription(c.getcity()); return node; // try { // return new beannode(c); // } catch (introspectionexception ex) { // exceptions.printstacktrace(ex); // return null; // } } now, whenever a new node is created, which happens when the user selects a new customer in the viewer, a new customer object is added to the lookup of the node. let's now change the editor module in such a way that its window will end up listening for customer objects being added to the lookup. first, set a dependency in the editor module on the module that provides the entity class, as well as the module that provides the persistence jars. next, change the editortopcomponent class signature to implement lookuplistener: public final class editortopcomponent extends topcomponent implements lookuplistener override the resultchanged so that the jtextfields are updated whenever a new customer object is introduced into the lookup: @override public void resultchanged(lookupevent lookupevent) { lookup.result r = (lookup.result) lookupevent.getsource(); collection coll = r.allinstances(); if (!coll.isempty()) { for (customer cust : coll) { jtextfield1.settext(cust.getname()); jtextfield2.settext(cust.getcity()); } } else { jtextfield1.settext("[no name]"); jtextfield2.settext("[no city]"); } } now that the lookuplistener is defined, we need to add it to something. here, we add it to the lookup.result obtained from the global context. the global context proxies the context of the selected node. for example, if "ford motor co" is selected in the tree hierarchy, the customer object for "ford motor co" is added to the lookup of the node which, because it is the currently selected node, means that the customer object for "ford motor co" is now available in the global context. that is what is then passed to the resultchanged, causing the text fields to be populated. all of the above starts happening, i.e., the lookuplistener becomes active, whenever the editor window is opened, as you can see below: @override public void componentopened() { result = utilities.actionsglobalcontext().lookupresult(customer.class); result.addlookuplistener(this); resultchanged(new lookupevent(result)); } @override public void componentclosed() { result.removelookuplistener(this); result = null; } since the editor window is opened when the application starts, the lookuplistener is available at the time that the application starts up. finally, declare the result variable at the top of the class, like this: private lookup.result result = null; run the application again and notice that the editor window is updated whenever you select a new node: however, notice what happens when you switch the focus to the editor window: because the node is no longer current, the customer object is no longer in the global context. this is the case because, as pointed out above, the global context proxies the lookup of the current node. therefore, in this case, we cannot use the global context. instead, we will use the local lookup provided by the customer window. rewrite this line: result = utilities.actionsglobalcontext().lookupresult(customer.class); to this: result = windowmanager.getdefault().findtopcomponent("customertopcomponent").getlookup().lookupresult(customer.class); the string "customertopcomponent" is the id of the customertopcomponent, which is a string constant that you can find in the source code of the customertopcomponent. one drawback of the approach above is that now our editortopcomponent only works if it can find a topcomponent with the id "customertopcomponent". either this needs to be explicitly documented, so that developers of alternative editors can know that they need to identify the viewer topcomponent this way, or you need to rewrite the selection model, as described here by tim boudreau. if you take one of the above approaches, you will find that the context is not lost when you switch the focus to the editortopcomponent, as shown below: note: since you are now using abstractnode, instead of beannode, no properties are shown in the properties window. you need to provide these yourself, as described in the nodes api tutorial . secondly, let's work on the undo/redo functionality. what we'd like to have happen is that whenever the user makes a change to one of the jtextfields, the "undo" button and the "redo" button, as well as the related menu items in the edit menu, become enabled. to that end, the netbeans platform makes the undoredo.manager available. declare and instantiate a new undoredomanager at the top of the editortopcomponent: private undoredo.manager manager = new undoredo.manager(); next, override the getundoredo() method in the editortopcomponent: @override public undoredo getundoredo() { return manager; } in the constructor of the editortopcomponent, add a keylistener to the jtextfields and, within the related methods that you need to implement, add the undoredolisteners: jtextfield1.getdocument().addundoableeditlistener(manager); jtextfield2.getdocument().addundoableeditlistener(manager); run the application and show the undo and redo functionality in action, the buttons as well as the menu items. the functionality works exactly as you would expect. you might want to change the keylistener so that not all keys cause the undo/redo functionality to be enabled. for example, when enter is pressed, you probably do not want the undo/redo functionality to become available. therefore, tweak the code above to suit your business requirements. thirdly, we need to integrate with the netbeans platform's save functionality: by default, the "save all" button is available in the netbeans platform toolbar. in our current scenario, we do not want to save "all", because "all" refers to a number of different documents. in our case, we only have one "document", which is the editor that we are reusing for all the nodes in the tree hirerarchy. remove the "save all" button and add the "save" button instead, by adding the following to the layer file of the customereditor module: when you now run the application, you will see a different icon in the toolbar. instead of the "save all" button, you now have the "save" button available. set dependencies on the dialogs api and the nodes api. in the editortopcompontn constructor, add a call to fire a method (which will be defined in the next step) whenever a change is detected: public editortopcomponent() { ... ... ... jtextfield1.getdocument().adddocumentlistener(new documentlistener() { public void insertupdate(documentevent arg0) { fire(true); } public void removeupdate(documentevent arg0) { fire(true); } public void changedupdate(documentevent arg0) { fire(true); } }); jtextfield2.getdocument().adddocumentlistener(new documentlistener() { public void insertupdate(documentevent arg0) { fire(true); } public void removeupdate(documentevent arg0) { fire(true); } public void changedupdate(documentevent arg0) { fire(true); } }); //create a new instance of our savecookie implementation: impl = new savecookieimpl(); //create a new instance of our dynamic object: content = new instancecontent(); //add the dynamic object to the topcomponent lookup: associatelookup(new abstractlookup(content)); } ... ... ... here are the two methods referred to above. first, the method that is fired whenever a change is detected. an implementation of the savecookie from the nodes api is added to the instancecontent whenever a change is detected: public void fire(boolean modified) { if (modified) { //if the text is modified, //we add savecookie impl to lookup: content.add(impl); } else { //otherwise, we remove the savecookie impl from the lookup: content.remove(impl); } } private class savecookieimpl implements savecookie { @override public void save() throws ioexception { confirmation message = new notifydescriptor.confirmation("do you want to save \"" + jtextfield1.gettext() + " (" + jtextfield2.gettext() + ")\"?", notifydescriptor.ok_cancel_option, notifydescriptor.question_message); object result = dialogdisplayer.getdefault().notify(message); //when user clicks "yes", indicating they really want to save, //we need to disable the save action, //so that it will only be usable when the next change is made //to the jtextarea: if (notifydescriptor.yes_option.equals(result)) { fire(false); //implement your save functionality here. } } } run the application and notice the enablement/disablement of the save button: note: right now, nothing happens when you click ok in the dialog above. in the next step, we add some jpa code for handling persistence of our changes. next, we add jpa code for persisting our change. do so by replacing the comment "//implement your save functionality here." the comment should be replaced by all of the following: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); entitymanager.gettransaction().begin(); customer c = entitymanager.find(customer.class, customer.getcustomerid()); c.setname(jtextfield1.gettext()); c.setcity(jtextfield2.gettext()); entitymanager.gettransaction().commit(); note: the "customer" in customer.getcustomerid() is currently undefined. add the line "customer = cust;" in the resultchanged (as shown below), after declaring customer customer; at the top of the class, so that the current customer object sets the customer, which is then used in the persistence code above to obtain the id of the current customer object. @override public void resultchanged(lookupevent lookupevent) { lookup.result r = (lookup.result) lookupevent.getsource(); collection c = r.allinstances(); if (!c.isempty()) { for (customer customer : c) { customer = cust; jtextfield1.settext(customer.getname()); jtextfield2.settext(customer.getcity()); } } else { jtextfield1.settext("[no name]"); jtextfield2.settext("[no city]"); } } run the application and change some data. currently, we have no "refresh" functionality (that will be added in the next step) so, to see the changed data, restart the application. here, for example, the tree hierarchy shows the persisted customer name for "toyota motor co": fourthly, we need to add functionality for refreshing the customer viewer. you might want to add a timer which periodically refreshes the viewer. however, in this example, we will add a "refresh" menu item to the root node so that the user will be able to manually refresh the viewer. in the main package of the customerviewer module, create a new node, which will replace the abstractnode that we are currently using as the root of the children in the viewer. note that we also bind a "refresh" action to our new root node. public class customerrootnode extends abstractnode { public customerrootnode(children kids) { super(kids); setdisplayname("root"); } @override public action[] getactions(boolean context) { action[] result = new action[]{ new refreshaction()}; return result; } private final class refreshaction extends abstractaction { public refreshaction() { putvalue(action.name, "refresh"); } public void actionperformed(actionevent e) { customertopcomponent.refreshnode(); } } } add this method to the customertopcomponent, for refreshing the view: public static void refreshnode() { entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); em.setrootcontext(new customerrootnode(children.create(new customerchildfactory(resultlist), true))); } now replace the code above in the constructor of the customertopcomponent with a call to the above. as you can see, we are now using our customerrootnode instead of the abstractnode. the customerrootnode includes the "refresh" action, which calls the code above. in your save functionality, add the call to the method above so that, whenever data is saved, an automatic refresh takes place. you can take different approaches when implementing this extension to the save functionality. for example, you might want to create a new module that contains the refresh action. that module would then be shared between the viewer module and the editor module, providing functionality that is common to both. run the application again and notice that you have a new root node, with a "refresh" action: make a change to some data, save it, invoke the refresh action, and notice that the viewer is updated. you have now learned how to let the netbeans platform handle changes to the jtextfields. whenever the text changes, the netbeans platform undo and redo buttons are enabled or disabled. also, the save button is enabled and disabled correctly, letting the user save changed data back to the database. create in this section, you allow the user to create a new entry in the database. right-click the customereditor module and choose "new action". use the new action wizard to create a new "always enabled" action. the new action should be displayed anywhere in the toolbar and/or anywhere in the menu bar. in the next step of the wizard, call the action newaction. note: make sure that you have a 16x16 icon available, which the wizard forces you to select if you indicate that you want the action to be invoked from the toolbar. in the new action, let the topcomponent be opened, together with emptied jtextfields: import java.awt.event.actionevent; import java.awt.event.actionlistener; public final class newaction implements actionlistener { public void actionperformed(actionevent e) { editortopcomponent tc = editortopcomponent.getdefault(); tc.resetfields(); tc.open(); tc.requestactive(); } } note: the action implements the actionlistener class, which is bound to the application via entries in the layer file, put there by the new action wizard. imagine how easy it will be when you port your existing swing application to the netbeans platform, since you'll simply be able to use the same action classes that you used in your original application, without needing to rewrite them to conform to action classes provided by the netbeans platform! in the editortopcomponent, add the following method for resetting the jtextfields and creating a new customer object: public void resetfields() { customer = new customer(); jtextfield1.settext(""); jtextfield2.settext(""); } in the savecookie, ensure that a return of null indicates that a new entry is saved, instead of an existing entry being updated: public void save() throws ioexception { confirmation message = new notifydescriptor.confirmation("do you want to save \"" + jtextfield1.gettext() + " (" + jtextfield2.gettext() + ")\"?", notifydescriptor.ok_cancel_option, notifydescriptor.question_message); object result = dialogdisplayer.getdefault().notify(msg); //when user clicks "yes", indicating they really want to save, //we need to disable the save button and save menu item, //so that it will only be usable when the next change is made //to the text field: if (notifydescriptor.yes_option.equals(result)) { fire(false); entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); entitymanager.gettransaction().begin(); if (customer.getcustomerid() != null) { customer c = entitymanager.find(customer.class, cude.getcustomerid()); c.setname(jtextfield1.gettext()); c.setcity(jtextfield2.gettext()); entitymanager.gettransaction().commit(); } else { query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); customer.setcustomerid(resultlist.size()+1); customer.setname(jtextfield1.gettext()); customer.setcity(jtextfield2.gettext()); //add more fields that will populate all the other columns in the table! entitymanager.persist(customer); entitymanager.gettransaction().commit(); } } } run the application again and add a new customer to the database. delete in this section, let the user delete a selected entry in the database. using the concepts and code outlined above, implement the delete action yourself. create a new action, deleteaction. decide whether you want to bind it to a customer node or whether you'd rather bind it to the toolbar, the menu bar, keyboard shortcut, or combinations of these. depending on where you want to bind it, you will need to use a different approach in your code. read the article again for help, especially by looking at how the "new" action was created, while comparing it to the "refresh" action on the root node. get the current customer object, return an 'are you sure?' dialog, and then delete the entry. for help on this point, read the article again, focusing on the part where the "save" functionality is implemented. instead of saving, you now want to delete an entry from the database. see also this concludes the article. you have learned how to create a new netbeans platform application with crud functionality for a given database. you have also seen many of the netbeans apis in action. for more information about creating and developing applications on the netbeans platform, see the following resources: netbeans platform learning trail netbeans api javadoc
December 8, 2009
by Geertjan Wielenga
· 232,067 Views
article thumbnail
Lombok Reduces Your Boilerplate Code
In this article, I show you the power of the product I stumbled upon this week: Project Lombok enables you to modify bytecode at compile code. First, I will detail what features Lombok brings you out-of-the-box. In the second part of this article, I will describe how to extend it to generate you own code. Introduction Since the dawn of JEE, complaints have been filed regarding the complexity of coding components. I consider EJB v2 a very good example of this complexity: for just a simple EJB, you have to provide the EJB class itself and a home and an interface for each access type (local and remote). This makes it complex, error-prone and more importantly gives you less time to focus on business code where the real value is. Two initiatives show the will to decrease the amount of boilerplate code needed when coding: the Spring Framework’s motto is to decrease JEE complexity. The boilerplate code is written once in the Spring framework and only used by projects. EJB v3 has taken into account the lessons from Spring and aim to reduce boilerplate code too, making local and remote interfaces unnecessary. Eventually, the next version of the specification will make the local and remote home optional too. The goal of Project Lombok is exactly the same as the previous initiatives but in order to do so, it uses another mechanism. Annotation processing Version 5 of the Java language introduced the concept of annotations, code meta-data that could be processed at compile time and/or runtime. Unfortunately, in JDK 5, processing annotations at compile is a 2-step process. First, you have to run the apt executable to process annotations, perhaps creating or modifying source files, then compile your sources with javac. That was not the best approach, so Java 6 removes apt and make javac able to manage annotations, streamlining the process to obtain a simpler single step computing. This is the path taken by Lombok. Project Lombok Lombok’s driving feature is to create code you need from annotations in order to reduce the amount of boilerplate code you have to write. It provides you with the following annotations that will change your code (if not your life) forever: @Getter and @Setter: create getters and setters for your fields @EqualsAndHashCode: implements equals() and hashCode() @ToString: implements toString() @Data: uses the four previous features @Cleanup: closes your stream @Synchronized: synchronize on objects @SneakyThrows: throws exceptions For example, while learning to code the OO way, you were drilled into making your fields private and into writing public accessors to access these fields: public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Since this is a bother to write, some (if not all) IDE have a feature to generate the accessors. It has some drawbacks: You have to manually remove the accessors if you remove the field It clutters your real code with boilerplate code Corollary: it takes a real effort to check whether an accessor already exist for a field in a long class Moreover, creating accessors manually is error-prone: I once searched for hours for a bug in code developed by a fellow developer and finally found the setter was wrong. Since getter / setter is only meta-data for a field, Lombok’s stance is to treat it like such: in Java, meta-data is managed with annotations. Look at the following code: import org.lombok.Getter; import org.lombok.Setter; public class Person { @Getter @Setter private String name; } I decompiled the generated class (using JAD) and it creates exactly the same bytecode, only the source code is more concise and less error-prone. When thinking, I found 3 arguments against using Lombok: The first argument against using such a strategy is that you can’t create a protected accessor like that. You’re wrong, Lombok is configurable: import lombok.AccessLevel; import org.lombok.Getter; import org.lombok.Setter; public class Person { @Getter @Setter(AccessLevel.PROTECTED) private String name; } And its true for all the provided annotations! Just look at them. The second argument against using Lombok is that you don’t know what it does behind the scene. It’s true, but the same could be said for AOP or CGLIB or whatever framework you’re using. The last argument and IMHO the only one valid enough is that it renders debugging more complex: but so is the use of Java dynamic proxies that Spring uses throughout its code, and still many projects use them. Use and installation Using Lombok is a 3-step process: Put the JAR on the classpath Add the annotation you want to use Compile with javac There’s a catch, though. Notice the last statement and the emphasis on javac. Since most (if not all) the developers you and I know focus a little bit on productivity, chances are you’re using a IDE. I do not know about NetBeans and fellows, but my favorite IDE Eclipse does not use javac to compile but its own internal compiler. Our friends from Lombok thought about that and Lombok is able to hook into Eclipse compiling process too. In order to do so, just launch lombok.jar and follow the instructions on you screen: it will just add 2 lines to your eclipse.ini. A word of advice (since I made the mistake): if you launch Eclipse with a command that takes parameters, such as a Windows shortcut, these parameters take precedence and eclipse.ini is silently ignored. Just to let you know… Lombok extensions To my knowledge, there’s currently only a single extension of Lombok called Morbok. It lets you create your classical private static final logger with just an annotation. The advantage of this is that Morbok automatically uses the fully qualified class name as the name of the logger so no more copy paste error. The disadvantage is that if you do not use Commons Logging as you logging framework, you have to configure each @Logger annotation with the framework you want to use, there’s no overall configuration: IMHO, that’s something that could be covered in the next version (is there’s one). Architecture First things first, Lombok needs a JDK 6 to compile since annotation processing is done in Java 5 with APT. For now, Lombok hooks into the compiling process immediately after the environment has built the AST for the class. It then passes the structure thus formed to each of its referenced handlers. There’s a single handler for each annotation: HandleGetter for @Getter, HandlerSetter for @Setter and so on. Handlers are, guess what, responsible for handling annotations. Extending Lombok Extending Lombok is a 3-step process: Create the annotation. Since the annotation is used at compile-time, it can be safely be discarded afterwards so its retention policy can be left to its default value (namely RetentionPolicy.SOURCE) Create the handler. A handler is a class that directly implements lombok.javac.JavacAnnotationHandler. Why directly? Because Lombok uses the ServiceProvider service and it’s one of its limitations Reference the fully qualified class name of the handler in a file named lombok.javac.JavacAnnotationHandler under META-INF/services The real coding takes place in step 2: the interface has a single method handle(AnnotationValues annotation, com.sun.tools.javac.tree.JCTree.JCAnnotation ast, JavacNode annotationNode). Notice the 2nd parameter package? It’s denotes Sun private implementation. It has some big drawbacks: The documentation is sparse if not completely unavailable. You go into unknown territory here Since the com.sun.tools.javac is not part of the public API, it can change at a moment’s notice. You can break your code with each update Remember that previously, I talked about this being only good for Java? That’s still true. If you want this new annotation to work under Eclipse, that’s another handler to write Example As an example, I coded an embryo for a @Delegate annotation. Such an annotation on a field indicates that the declaring class should have the same public methods as the field’s class and each method’s body should be a call to its delegate’s method. public class Delegator { @Delegate private DelegateObject object; ... } public class DelegateObject { public void doSomething() { ... } } The previous code should generate the same bytecode as the following code: public class Delegator { private DelegateObject object; public void doSomething() { object.doSomething(); } ... } As yet: it does not handle generics the only handler provided is for javac it is not configurable The final implementation is left for the brave readers: original sources are here in Eclipse/Maven format. Conclusion Some improvements could quickly be made to Lombok. First, I don’t like the monolithic structure the JAR has. IMHO, it could be nicely decoupled into 3 separate JARs: the Lombok agent itself, the provided annotations and associated handlers and finally, the installer. Moreover, coding two handlers for each annotation is a lost of time. What if you need to support NetBeans too? Perhaps using the Service Provider is a mistake… Finally, depending on Sun’s internal compiler API is too big a risk. I think that if Lombok could provide a facade to this API, it could be less risky for enterprise to take this road and the bridging could be made by people who understand the API (the Lombok team) and not base developers (like myself). All in all, and despite these flaws, Lombok looks like a very promising project that could well mimic Spring’s success. That’s what I wish it anyway because it’s real sideway thinking that brings much added value: good luck for the future! To go further: Project Lombok Lombok’s Javadoc Morbok From http://blog.frankel.ch
December 7, 2009
by Nicolas Fränkel
· 21,196 Views · 1 Like
article thumbnail
JAXB Customization of xsd:dateTime
A small JAXB puzzle: how to define a custom element to serialize Date objects with the TimeZone information? Piece of cake, isn't it? Try it yourself and you will be surprised with the tricky details. A friend of mine gave me a JAXB challenge this week: his company already uses a customization of the xsd:date type in a legacy code - mapped to a proprietary type instead of the default Calendar type. Now they also need to represent Calendar objects in their application schema, so they need to model the date objects as a custom type. My first thought was about a five minutes hack, just defining an element based on the xsd:date and use the JAXB customization to map the new type to the Java Calendar type. After my five minutes I got few issues: The default customization of Calendar in JAXB doesn't serialize the Time information of a date. Ok, let's create a custom binder class and hack the way we want to write and read our data. If you use xsd:dateTime instead of a simple xsd:date, the default adapter of JAXB doesn't work anymore. Other surprise: you can't use the java.text.SimpleDateFormat to serialize Date objects because the String representation of the TimeZone provided by Java is not compatible with the XML specification. - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") produces 2009-12-06T15:59:34+0100 - the expected format for the Schema xsd:dateTime type is 2009-12-06T15:59:34+01:00 You got the difference? Yes, the stupid missed colon in the time zone representation makes the output of the SimpleDateFormat incompatible with the XSD Schema specification. Yes, unbelievable but you need to handle that detail programatically. You can try by yourself but instead of proving you the details I wrote down my hack solution. If you know a more elegant solution, please give me your feedback. Remember the original problem: to not use the xsd:dateTime directly since it is already in use by other customization. Also: your customization should support a date and time representation, including the time zone. Below you find a transcription of the sample project I created to illustrate the solution, to facilitate the copy paste and also to allow you to check the solution in case you don't want or you can't compile and run the project. Otherwise, just download the complete project. To compile and run the project, open a terminal and type the following line commands in the folder you unzipped the project: mvn clean compile test eclipse:eclipse The sample Maven project First step, to create the maven project and configure the JAXB plugin in the pom.xml. To create the project I used the Maven default J2SE archetype: mvn archetype:create -DgroupId=cejug.org -DartifactId=jaxb-example mvn compile eclipse:eclipse Then you can import the project in your preferred IDE and configure the JAXB plugin in the pom.xml: 4.0.0 cejug.org jaxb-example jar 1.0-SNAPSHOT jaxb-example http://maven.apache.org junit junit 3.8.1 test maven2-repository.dev.java.net Java.net Maven 2 Repository http://download.java.net/maven/2 org.apache.maven.plugins maven-compiler-plugin 2.0.2 1.6 1.6 org.jvnet.jaxb2.maven2 maven-jaxb2-plugin generate ${basedir}/src/main/resources/schema **/*.xsd true false true yes true After that, I created the sample schema /jaxb-example/src/main/resources/schema/sample-binding.xsd: Inspired by this blog I created the custom binder org.cejug.binder.XSDateTimeCustomBinder: package org.cejug.binder; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class XSDateTimeCustomBinder { public static Date parseDateTime(String s) { DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); try { return formatter.parse(s); } catch (ParseException e) { return null; } } // crazy hack because the 'Z' formatter produces an output incompatible with the xsd:dateTime public static String printDateTime(Date dt) { DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); DateFormat tzFormatter = new SimpleDateFormat("Z"); String timezone = tzFormatter.format(dt); return formatter.format(dt) + timezone.substring(0, 3) + ":" + timezone.substring(3); } } Then I created a JUnit class with the following test method: package cejug.org; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.cejug.sample.ElementType; import org.cejug.sample.ObjectFactory; import org.xml.sax.SAXException; public class JaxbSampleTest extends TestCase { private static final String UTF_8 = "UTF-8"; private static final File TEST_FILE = new File("target/test.xml"); public JaxbSampleTest(String testName) { super(testName); } public static Test suite() { return new TestSuite(JaxbSampleTest.class); } @Override protected void setUp() throws Exception { super.setUp(); if (TEST_FILE.exists()) { if (!TEST_FILE.delete()) { fail("impossible to delete the test file, please release it and run the test again"); } } } public void testApp() { ObjectFactory xmlFactory = new ObjectFactory(); ElementType type = new ElementType(); Date calendar = GregorianCalendar.getInstance(TimeZone.getDefault()) .getTime(); type.setJdate(calendar); JAXBElement element = xmlFactory.createElement(type); try { writeXml(element, TEST_FILE); JAXBElement result = read(TEST_FILE); assertEquals(calendar.toString(), result.getValue().getJdate().toString()); } catch (Exception e) { fail(e.getMessage()); } } private void writeXml(JAXBElement sample, File file) throws JAXBException, IOException { FileWriter writer = new FileWriter(file); try { JAXBContext jc = JAXBContext.newInstance(ElementType.class .getPackage().getName(), Thread.currentThread() .getContextClassLoader()); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_ENCODING, UTF_8); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(sample, writer); } finally { writer.close(); } } @SuppressWarnings("unchecked") public JAXBElement read(File file) throws JAXBException, SAXException, IOException { InputStreamReader reader = new InputStreamReader(new FileInputStream( file)); try { JAXBContext jc = JAXBContext.newInstance(ElementType.class .getPackage().getName(), Thread.currentThread() .getContextClassLoader()); Unmarshaller unmarshaller = jc.createUnmarshaller(); SchemaFactory sf = SchemaFactory .newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = sf.newSchema(Thread.currentThread() .getContextClassLoader().getResource( "../classes/schema/sample-binding.xsd")); unmarshaller.setSchema(schema); JAXBElement element = (JAXBElement) unmarshaller .unmarshal(reader); return element; } finally { reader.close(); } } } That's it, I hope it can save your next five minutes of hack :) From http://weblogs.java.net/blog/felipegaucho
December 7, 2009
by Felipe Gaúcho
· 40,464 Views
article thumbnail
jQuery, Each() and Async Gets
One of the things to keep in mind when using jQuery is that nothing is a blocking call. Sure, there is a certain sequence to when things operate. But, to be safe, you should always assume that step two will happen during step one. No where is this more evident than when retrieving content from a URL and inserting that content in your page. The temptation is to write code that looks something like this $.each(json, function(index, entry) { jQuery.get(entry['url'], function(html) { // insert the HTML here. } } The problem with this is that jQuery.get is an asynchronous call. This means that once the get has fired, the each loop will continue. This can cause all kinds of trouble for you, including having a complete iteration skipped, or if you are doing some kind of concatenation prior to inserting the HTML, having HTML for one iteration showing up in the middle of another. Not exactly what you had in mind, eh? But there is a fix. Use the ajax call instead and specify async:false to force the call to complete before allowing another call. $.each(json, function(index, entry) { jQuery.ajax({ url: directory + '/' + entry['url'] , success: function(html) { // insert the HTML here. } }, async: false }); Note too that using ajax without the async: false is the same as just using get.
December 3, 2009
by Dave Bush
· 16,263 Views
article thumbnail
A Groovy ride on Camel
Apache Camel is a routing and mediation engine which implements the Enterprise Integration Patterns. But don't let the words Enterprise Integration scare you off. Camel is designed to be really light weight and has a small footprint. It can be reused anywhere, whether in a servlet, in a Web services stack, inside a full ESB or a standalone messaging application. Camel makes it really simple to implement messaging application. So there are not many reasons why you could not use it in non-enterprise application. In fact, it is possible to use Camel as a tool, similar to the way you use scripting languages. For example, you could fire up the Camel Web Console and define a messaging application without write a single line of code. This article is a getting-started type of tutorial. As you might have guessed, I'm going to use Groovy as the programming language. And the programs in this article are intend to be ran with Groovysh, the Groovy Shell. Reasons: Groovy is concise, expressive and has less noice than Java. All programs in this article are just a couple dozen lines long and should be real easy to follow along. Using Groovysh allows the reader to interact with the application. I'm a Linux guy and am comfortable with VIM and working in command line. So bare with me. Putting the pieces together First, I'm going to write a simple program to make sure I'm able to talk to Camel in Groovy. I'm not using an IDE like Eclipse, nor creating a project, nor going to use any build tools like Maven. Any text editor will be sufficient. Save the following code to a file named CamelDemo.groovy (source download). import groovy.grape.Grape Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0") class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { void configure() { from("direct://foo").to("mock://result") } } mrb = new MyRouteBuilder() ctx = new org.apache.camel.impl.DefaultCamelContext() ctx.addRoutes mrb ctx.start() p = ctx.createProducerTemplate() p.sendBody "direct:foo", "Camel Ride for beginner" e = ctx.getEndpoint("mock://result") ex = e.exchanges.first() println "INFO> ${ex}" This little program does a couple things: Imports the camel-core jar using Grape.grab() Defines a our custom RouteBuilder, which defines a simple route between a direct:foo and a mock:result enpoints. Instantiates the CamelContext, adds our custom RouteBuilder to it and starts Camel by ctx.start(). Tests the route by sending a message exchange using the producerTemplate obtained from the CamelContext Lookups the mock:result endpoint (ctx.getEndpoint("mock:result")) and dislays the first Exchange, which should contain the message we just sent. Now start the groovysh in a command window and load the program: $ groovysh groovy:000> load CamelDemo.groovy you should see a bunch of output and then the output from the script: INFO> Exchange[Message: Camel Ride for beginner] ===> null groovy:000> At this point, you can interact with the program via groovysh. For example the following shows a few things you can do. groovy:000> ctx.routes ===> [EventDrivenConsumerRoute[Endpoint[seda://foo] -> UnitOfWork(Channel[sendTo(Endpoint[mock://result])])]] groovy:000> ctx.components ===> {mock=org.apache.camel.component.mock.MockComponent@14f2bd7, seda=org.apache.camel.component.seda.SedaComponent@c759f5} groovy:000> ctx.endpoints ===> [Endpoint[seda://foo], Endpoint[mock://result]] groovy:000> ctx.endpoints[1].exchanges ===> [Exchange[Message: Camel Ride for beginner]] groovy:000> ctx.endpoints[1].exchanges[0].in.body ===> Camel Ride for beginner groovy:000> p.sendBody("seda:foo", "Camel Kicking") ===> null groovy:000> e.exchanges ===> [Exchange[Message: Camel Ride for beginner], Exchange[Message: Camel Kicking]] This is it for our first Groovy/Camel program. For the curious, you can actually modify the program and reload it without terminating and restarting groovysh. Camel Stock Quote This is a simple stock quote application. Initially, I planed to walk you thru the development steps, from adding a simple bean as a Processor to transforming it to a Multi-Channel, Multi-Data-Format service application. But after I've finished developing the program, it turns out that it is too simple to justify for such elaboration. To save your time and mine, I'm just going to show you the final version right here. Take a look at it, and if you can understand what it does, then may be you should skip the rest of this article :) Save the following code to a file named StockQuote.groovy (source download). import groovy.grape.Grape Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-jetty", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-freemarker", version:"2.0.0") class QuoteServiceBean { public String usStock(String symbol) { "${symbol}: 123.50 US\$" } public String hkStock(String symbol) { "${symbol}: 90.55 HK\$" } } class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { void configure() { from("direct://quote").choice() .when(body().contains(".HK")).bean(QuoteServiceBean.class, "hkStock") .otherwise().bean(QuoteServiceBean.class, "usStock") .end().to("mock://result") from("direct://xmlquote").transform().xpath("//quote/@symbol", String.class).to("direct://quote") //curl -H "Content-Type: text/xml" http://localhost:8080/quote?symbol=IBM from('jetty:http://localhost:8080/quote').transform() .simple('').to("direct://xmlquote").choice() .when(header("Content-Type").isEqualTo("text/xml")).to("freemarker:xmlquote.ftl") .otherwise().to("freemarker:htmlquote.ftl") .end() } } ctx = new org.apache.camel.impl.DefaultCamelContext() mrb = new MyRouteBuilder() ctx.addRoutes mrb ctx.start() p = ctx.createProducerTemplate() //p.sendBody("direct:quote", "00005.HK") //p.sendBody("direct:xmlquote", "") //p.sendBody("direct:xmlquote", "") e = ctx.getEndpoint("mock://result") //e.exchanges.each { ex -> // println "INFO> in.body='${ex.in.body}'" //} OK, you are still here. It is assumed that: We have two market data providers, one for U.S. market and the other for Hong Kong market. An existing QuoteServiceBean class has been implemented as a POJO. It has two methods, usStock() and hkStock(). It is part of a legacy system, it works great, it hides the underlying details of interacting with the data providers. No one understands it and no one dares to modify it. We would like to use the existing QuoteServiceBean to provide a stock quote service that can be consume easily. i.e. Multi-Channel and Multi-Data-Format. Content Based Router and Message Translator from("direct://quote").choice() .when(body().contains(".HK")).bean(QuoteServiceBean.class, "hkStock") .otherwise().bean(QuoteServiceBean.class, "usStock") .end().to("mock://result") The first route (start at line 17) represented by the direct:quote endpoint. It routes the message according to the content of the body of the exchange, which it's assumed to contain the stock symbol. When the body of the exchange contains the string ".HK" the hkStock(String symbol) of QuoteServiceBean is called, otherwise the usStock(String symbol) of QuoteServiceBean is called. Notice that the route DSL almost reads like plain English! Let us try it out. First start groovysh, load the program and send two messages to the direct:quote endpoint: jack@localhost tmp]$ groovysh Groovy Shell (1.6.6, JVM: 1.6.0_11) groovy:000> load StockQuote.groovy .............. groovy:000> p.sendBody("direct:quote", "00001.HK") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: 00001.HK: 90.55 HK$] groovy:000> p.sendBody("direct:quote", "SUNW") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: SUNW: 123.50 US$] groovy:000> That is it, our simple content-based router successfully routes request to the corresponding processor methods. XML Quote Request, message Transform from("direct://xmlquote").transform().xpath("//quote/@symbol", String.class).to("direct://quote") This next route simply accepts requests in XML, transforms the request and chains it to direct://quote. With this, we've added the capability to accept requests in XML format! We are using XPath here to expression our transform. Check out the hosts of Expression Langauges supported by Camel. Let us try it out: groovy:000> p.sendBody("direct:xmlquote", "") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: GOOG: 123.50 US$] groovy:000> Multi-Channel, Multi-Data-Format Provisioning Grape.grab(group:"org.apache.camel", module:"camel-jetty", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-freemarker", version:"2.0.0") // ........... lines removed for brevity ............. from('jetty:http://localhost:8080/quote').transform() .simple('').to("direct://xmlquote").choice() .when(header("Content-Type").isEqualTo("text/xml")).to("freemarker:xmlquote.ftl") .otherwise().to("freemarker:htmlquote.ftl") .end() Here we use the camel-jetty to expose an endpoint jetty:http://localhost:8080/quote to our quote service. Note that camel-jetty is not part of camel-core. That is why we have to grab it into our program. The HTTP request is translate into XML using simple expression. Note that the camel-jetty has kindly extracted the request parameters as well as the HTTP header and placed them on the Message header. So the request parameter symbol is access as ${header.symbol} in the expression. Next we simply chain the message exchange to the direct:xmlquote endpoint. The result from direct:xmlquote went thru another translation, which depends on the content-type of the orginating HTTP request. Here, I make use of the camel-freemarker to generate the desire output. So we need to create the two Freemarker templates: htmlquote.ftl ${body} xmlquote.ftl ${body} So let us see it in action, I'm going to use curl to make HTTP requests. Do this on another command window: [jack@localhost tmp]$ curl http://localhost:8080/quote?symbol=IBM IBM: 123.50 US$ [jack@localhost tmp]$ curl http://localhost:8080/quote?symbol=00001.HK 00001.HK: 90.55 HK$ [jack@localhost tmp]$ And to request XML content: [jack@localhost tmp]$ curl -H "Content-Type: text/xml" http://localhost:8080/quote?symbol=IBM IBM: 123.50 US$ [jack@localhost tmp]$ That's about it for our multi-channel/multi-data-format ser vice provision. Summary In this tutorial, I hoped to illustrate how Camel supports message passing paradigm style of application development. Camel provides all sort of components to help you build processing pipelines. All you need is to implement your business logic as simple POJOs and let Camel handle all the translating, routing, filtering, spliting and forwarding for you. Not shown in this tutorial is how to consume external resources and services from within a route. No sweat, it is just as easy. Camel integrates nicely with Spring as well as Guice, but works nicely on its own. It won't be in your way if you don't need DI support in your application. As they say: Keep the simple easy. Camel works nicely in a JBI environment like ServiceMix and OpenESB. Camel is OSGI-ready and tracks newly deployed bundles for Route definitions at runtime. So you can gear it all to way up to be part of an enterprise SOA infrastructure. Disclaimer, I'm not an experienced Camel user and still learning. Thank you for staying up with me.
December 3, 2009
by Jack Hung
· 26,014 Views
  • Previous
  • ...
  • 880
  • 881
  • 882
  • 883
  • 884
  • 885
  • 886
  • 887
  • 888
  • 889
  • ...
  • 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
×