Escolar Documentos
Profissional Documentos
Cultura Documentos
Migrating a Spring Framework Java Application to Microsoft Windows Azure and Windows Azure SQL Database
TM
Technical Reviewers: Gregory Leake, Microsoft Corporation Published: October, 2013 Applies to: Windows Azure and Windows Azure SQL Database Download code: https://github.com/Logic2020Inc/spring-petclinic-mod Live Application running on Windows Azure: http://petclinic.cloudapp.net/ Summary: This guide is written for Java developers to demonstrate how to migrate a typical Java application to the Windows Azure cloud. While the tutorial focuses on a popular Spring Framework sample application, the Java PetClinic, the tutorial will introduce you to the Windows Azure Java SDK, Windows Azure Caching using memcached, Windows Azure Cloud Services, Windows Azure SQL Database, and a variety of other technologies that will be used in many other types of Java applications deployed on Windows Azure.
Copyright
The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication. This white paper is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, AS TO THE INFORMATION IN THIS DOCUMENT. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in, or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.
Microsoft, SQL Server, Windows Server, SharePoint, Excel are trademarks of the Microsoft group of companies.
Page 2
Contents
I. II. III. Executive Summary ......................................................................................................................................... 5 Windows Azure Cloud Services or Windows Azure Virtual Machines? .......................................................... 5 Spring Framework on the Windows Azure Platform ................................................................................... 6
About Windows Azure ........................................................................................................................................ 6 IV. Pet Clinic on Azure: High-Level Architecture ..................................................................................................... 7 Defining Key Windows Azure Services ................................................................................................................ 7 Windows Azure Worker Role .......................................................................................................................... 8 Windows Azure SQL Database ........................................................................................................................ 8 Windows Azure Cache Service ........................................................................................................................ 8 Typical Tiered Architecture of a Web Application .............................................................................................. 8 Spring Framework Pet Clinic on Windows Azure ................................................................................................ 9 Apache Tomcat 7.0 .......................................................................................................................................... 9 Spring Data JPA .............................................................................................................................................. 10 Memcached ................................................................................................................................................... 10 High-Level Windows Azure Application Lifecycle ............................................................................................. 11 Local Development ........................................................................................................................................ 12 Local Windows Azure Emulator Deployment ................................................................................................ 12 Windows Azure (Staging/Production) Deployment ...................................................................................... 12 V. Windows Azure Java Application Lifecycle: Prerequisites................................................................................ 12 VI. Windows Azure Java Application Lifecycle Development Environment Configuration Steps ........................ 13 Step 0: Install Spring Tool Suite ......................................................................................................................... 13 Step 1: Install the Windows Azure Plugin for Eclipse with Java ........................................................................ 13 Step 2: Download the Pet Clinic source files..................................................................................................... 14 Step 3: Import Pet Clinic into the Eclipse (STS) project workspace .................................................................. 14 Step 4: Add Tomcat into the Eclipse (STS) server list ........................................................................................ 16 Step 5: Add the Microsoft JDBC 4.0 Driver to Pet Clinics project library. ........................................................ 18 Step 6: Create a Windows Azure SQL Database ............................................................................................... 20 Step 7: Get connection string information from the Windows Azure Portal ................................................... 21
October 11, 2013 Page 3
Step 8: Enable Database Connections to Windows Azure SQL Database......................................................... 22 Step 9: Configure LogBack to use Windows Azure SQL Database .................................................................... 27 Step 10: Inject Exception Handling for Transient Faults via AOP...................................................................... 29 Step 11: Inject Exception Handling for Transient Faults via AOP...................................................................... 31 Step 12: Add Memcached to PetClinic via AOP ................................................................................................ 32 VII. Windows Azure Java Application Lifecycle ..................................................................................................... 35 Deployment Consideration: Modifying Code to Maintain Database during Instance Redeployments .......... 35 VIII. Windows Azure Java Application Lifecycle: Creating a New Azure Deployment Project ............................. 36 Step 1: Export WAR File..................................................................................................................................... 36 Step 2: Create a Windows Azure Deployment Project ..................................................................................... 37 Import WAR File............................................................................................................................................. 39 Step 3: Deploy to the Windows Azure Compute local emulator ...................................................................... 42 Step 4: Publish to the Windows Azure Cloud: Staging and Production ............................................................ 43 IX. Reference Articles ............................................................................................................................................ 44
Page 4
I.
Executive Summary
Windows Azure is Microsoft's application platform for the public cloud. You can use this platform in many different ways. For instance, you can use Windows Azure to build a web application that runs and stores its data in Microsoft datacenters. You can use Windows Azure just to store data, with the applications that use this data running on-premises (that is, outside the public cloud). You can use Windows Azure to create virtual machines for development and test or to run Microsoft SQL Server, mySQL and other applications. You can use Windows Azure to build massively scalable applications with lots and lots of users. Because the platform offers a wide range of services, all of these things-and more-are possible. Most importantly, Windows Azure is an open cloud platform, and supports a wide variety of programming languages and frameworks, including Microsoft .NET, Java, Node.js, PHP, Python and Ruby. This guide is written specifically for Java developers to demonstrate how to migrate a typical Java application to the Windows Azure cloud. While the tutorial focuses on a popular Spring Framework sample application (the Java PetClinic); the tutorial will introduce you to the Azure Java SDK, Windows Azure Caching using memcached, Windows Azure Cloud Services, Windows Azure SQL Database, and a variety of other technologies that would be used in many other types of Java applications.
II.
Fundamentally, there are two different ways to run an application layer, such as a Web site, on Windows Azure. The first is via Platform as a Service (PaaS) via Azure Cloud Services. The second is via Infrastructure as a Service (IaaS) via Windows Azure Virtual Machines (VMs). With either, the developer chooses from one of eight worldwide data centers (four in the U.S., two in Europe, and two in Asia) to host their application. With Windows Azure Cloud Services, the developer just focuses on the application, and the platform automatically provisions and maintains the instances (under the covers these are Windows Hyper-V VMs) upon which the application layer runs. The instances can be horizontally scaled from one to several hundred clones, and load balancing is automatic. While the instances can be sized (with different numbers of virtual cores and memory), the instances are fundamentally managed by Windows Azure, including all patching and security updates of the OS layer. This guide focuses on running the Java Pet Clinic sample application on Windows Azure Cloud Services. With Windows Azure Virtual Machines, the developer creates his/her own VM image, and is responsible for installing and managing that VM including any software to be installed on the VM. For Java developers, there are a variety of pre-built VM images available, including Windows and several distributions of Linux. This is also a great way to run Java applications in the Windows Azure Cloud; as the developer has low-level control of the OS and VM, and can install software such as mySQL directly on any number of VMs, to build-out a complete application from application layer to data layer. Most Java applications will simply migrate with little or no code changes required. Load balancing can also be setup such that multiple VMs (perhaps running Tomcat/JSP layer) are load balanced via round-robin. Unlike Azure Cloud Services, however, the developer must manage the VM including any security patching just as if the VM was running on-premises. In addition, the hourly compute rate for a given instance (VM) size is higher. While this guide focuses on Java running on Windows Azure Cloud
October 11, 2013 Page 5
Services, we encourage developers to also try out Windows Azure Virtual Machines, using either Windows or Linux VMs.
III.
This guide will help Spring Framework developers migrate their applications to the Windows Azure Platform. Spring Frameworks recently updated PetClinic sample was chosen because it is a familiar vehicle for demonstrating several enterprise technologies that are used to create scalable J2EE applications such as Spring Data JPA, MVC, AOP, JMX, EhCache, and Logback. We will be extending PetClinic by injecting transient fault handling and Memcached on Azure Cache via AOP. For Java developers who are familiar with Eclipse and STS, Microsoft has provided the Windows Azure Toolkit for Eclipse with Java. This toolkit provides the following resources for aiding in Java development in Eclipse on Windows Azure: Windows Azure Plugin for Eclipse with Java Microsoft JDBC 4.0 Driver for SQL Server Package for Apache Qpid Client Libraries for JMS Package for Windows Azure Libraries for Java Windows Azure Access Control Services Filter Windows Azure Common Plugin
In this guide, we will be using the Windows Azure Plugin for Eclipse with Java and the Microsoft JDBC 4.0 Driver for SQL Server. The plugin to Eclipse provides Java wrappers for Windows Azure services and a Windows Azure emulator.
Page 6
applications to the cloud using Worker Roles, while reducing time on operations tasks.
LB
LB
Storage
Page 7
Windows Azure Worker Role A Worker Role is a deployable compute package that allows Windows Azure the ability to manage many aspects of data center operations such as OS patching, monitoring, deploying, and hardware-failure recovery. The Worker Role deployment can later be scaled out via the Windows Azure Portal UI, or by using the Windows Azure REST-API. The ability to scale a deployment from a single package is a significant advantage that Worker Roles provide. Windows Azure SQL Database Windows Azure SQL Database extends SQL Server capabilities to the cloud. You can easily provision and deploy relational database solutions. Benefits include manageability, high availability, scalability, and a familiar ER model. (Source: MSDN Windows Azure SQL Database) Windows Azure Cache Service Windows Azure Caching is an in-memory, distributed object cache that can be used to boost application performance. It can be easily used with Java as it supports a standard memcached interface. As user load increases, the Cache helps applications be more responsive, allowing your applications to scale. Data you store in the cache is accessible from multiple instances of your application enabling state to be easily and quickly shared between instances. Uses of the cache include centrally storing session state across multiple loadbalanced instances of your application layer; as well as caching frequently accessed database query results or any other type of Java object. Windows Azure Caching adds additional control and resilience options like high availability to ensure that your cached data is resilient. (See: Windows Azure Caching and Memcached Wrapper for Windows Azure Caching)
Page 8
LB
LB
Worker Role
LB
Storage
Figure 3: Worker Role Architecture Apache Tomcat 7.0 In this example, we are using Tomcat 7.0 as our servlet container; however other servlet containers such as Jetty or Websphere can be used. For the purposes of distributed cache as workers scale, Memcached is integrated with Windows Azure Caching Services. To the Memcached Client the integration is seamless.
Page 9
Spring Data JPA The Pet Clinic sample illustrates many persistence layer interfaces, such as Spring Data JPA, JPA and JDBC. Here we are using Spring Data JPA. To handle database connectivity with Windows Azure SQL Database, we are using the Microsoft Java Database Connectivity Driver (JDBC) 4.0 that is provided in the Windows Azure Toolkit for Java. We will also be showing how to handle transient faults. Memcached Memcached is a high-performance, distributed memory object caching system, intended for increasing dynamic web applications by alleviating database load. In our sample application, we have demonstrated how Memcached can be implemented as a performance/scalability enhancer. There are two approaches available for implementing memcache for a Windows Azure application: the Dedicated Caching roles approach, and the Co-located approach. From a developer perspective, either approach supports the standard memcache API calls. The only change you should have to make to existing memcache implementations is the endpoint.
Co-located Role VS Dedicated Role
Memcache Enabled Application Client Shim handles translation locally Client Shim uses Windows Azure Cache Protocol
Worker Role
Network call for re-hash Server Gateway uses Memcache wire protocol
Worker Role
Shim
Cache Server
Cache Server
Cache Server
Cache Server
Cache Server
Cache Server
Cache Server
Cache Server
Cache Server
Storage
Memcache Server Gateway (Co-located Cache) The server gateway approach (generally used with Co-located Cache) offers very simple deployment. No shim is required. However, this approach has performance limitations in some scenarios, because memcache and Windows Azure Caching Service use different hashing algorithms, resulting in the need to re-hash keys to determine which server a key should be stored on. Another consideration is that this approach only has
Page 10
available space remaining on the instances deployed in your cluster. If you have 5 web heads then you have 5 cache servers. We will be focusing on this method here.
Memcache Client Shim (Dedicated Cache) The client shim (generally used with a Dedicated Cache), on the other hand, is installed on the client application (which may be hosted on Windows Azure), and provides a memcache protocol handler for the application, with calls translated locally to Windows Azure Caching API calls which are sent to the cache servers. This results in better performance because there are no extra network hops for re-hashing keys, but deployment requires installation of the client shim on application roles, whereas the server gateway approach does not require any installation or setup steps on the client. Another advantage is that since a dedicated instance is used for cache you have better control over the space available to cache.
Page 11
Local Development You can develop your Java application locally in Eclipse(STS). For simplicity in this sample, your JDBC connections will point to your database hosted in Windows Azure. You could also have a local database in Azure using the emulator. But here we are hosting our development database in Azure to keep deployment steps across the lifecycle consistent. Also we need to be sure that Memcached service is running. The project files assume you are running Memcached locally. If you are running Memcached remotely you need to update ~src\main\resources\spring\tools-config.xml. Change the address property of the defaultMemcachedClient bean. Local Windows Azure Emulator Deployment When you are ready to test the deployment of your worker role package you can deploy locally to Windows Azure emulator services. Details on Memcached client changes below. Windows Azure (Staging/Production) Deployment Finally, when you are ready to deploy to staging and production you will package up your application for deployment to Windows Azure using the provided Eclipse (STS) plugin which includes an easy to use wizard that will guide you through the steps. We will cover this in detail in this guide.
Page 12
VI. Windows Azure Java Application Lifecycle Development Environment Configuration Steps
At a high-level, the configuration steps to set up a development environment for this project are as follows: 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. Install Spring Tool Suite (STS) Install the Windows Azure Plugin for Eclipse with Java Download the Pet Clinic source files Import Pet Clinic into STS project workspace Add Tomcat into to STS server list (assumes Tomcat is already installed) Add the Microsoft JDBC 4.0 Driver to Pet Clinics project library. Create Windows Azure SQL database Get connection string information from the Windows Azure Portal Enable Database Connections to Windows Azure SQL Database Configure LogBack to use Windows Azure SQL Database Inject Exception Handling for Transient Faults via AOP Add Memcached to PetClinic via AOP Create Azure deployment package in STS Configure Azure deployment by adding in Azure subscription
Step 1: Install the Windows Azure Plugin for Eclipse with Java
1. Start Eclipse(STS) 2. Click the Help dropdown menu and select Install New Software
Page 13
3. A new window appears. In the Work With text box, type http://dl.msopentech.com/eclipse and then click Add. Name the repository Windows Azure http://dl.msopentech.com/eclipse. The Windows Azure Toolkit for Java software downloads will appear.
4. Click Next and then click Finish. If you are prompted to restart, please do so.
Step 3: Import Pet Clinic into the Eclipse (STS) project workspace
1. Open Eclipse (STS). On your dashboard, right-click in the Package Explorer Window. 2. Scroll down, and select Import.
4. The Import Projects window opens. Here you will select the local directory structure that has the Pet Clinic, navigating to the base folder that has the POM.XML file. Select the folder. 5. Click Next and Finish. 6. Your Pet Clinic source code is now loaded into development environment. Developers Note: If you are building the project by using Maven, or import by using an Existing Maven Project, Eclipse (STS) will build using a different JRE System Library. You need to have the JRE System Library set to jdk 1.7.0_09, otherwise you may get a jdbc.BadSqlGrammarException exception when deploying.
Page 15
3. A new window will open. Under Select the server type, open the Apache Folder and select Tomcat 7.0..
5. Notice the path here is to the local installed instance of Tomcat. In later steps, while creating a deployment package for Azure, we will need a clean unzipped version of Tomcat that has not been installed. 6. Click Next and then add the sample application to the Configured Resources window.
7. Click Finish to close to wizard. 8. Your Tomcat server has now been added to your server list in STS.
Page 17
Step 5: Add the Microsoft JDBC 4.0 Driver to Pet Clinics project library.
1. If you have not already done so, download the Microsoft JBDC 4.0 driver by clicking here. 2. Open Eclipse(STS). In the Package Explorer Tab box, open the right-click menu and select Properties.
3. A new window opens. In the left navigation area, select Java Build Path. 4. Select the Libraries tab, and select the Add Library button.
Page 18
5. In the Add Library window, select the Microsoft JDBC 4.0 Driver for SQL Server and then click Finish.
6. This is what your Package Explorer should look like at the end of this step. Notice the toolbar now has the Windows Azure buttons, and the Microsoft JDBC Driver 4.0 is added to your project.
Page 19
3. Select Data Services, then select SQL Database, and finally select Quick Create
4. Select a 3-Month Free Trial or another subscription 5. Provide a database name, as well as a login name and password. 6. Select Create SQL Database.
Page 20
Step 7: Get connection string information from the Windows Azure Portal
1. 2. 3. 4. Log onto Windows Azure Portal Click on the Database in the left navigation Select your database On the lower-right hand side of the screen, select Show Connection Strings. Save string for later.
Developers Note: Notice the Allow the connection in firewall rules section. You most likely will not have to make any configuration changes to your firewall. However, this will all depend on the environment that the application is running in. Click on the link to add IP address to October 11, 2013 Page 21 firewall rules.
Page 22
alter table vet_specialties add constraint fk_vet_specialties_vets foreign key (vet_id) references vets(id); alter table vet_specialties add constraint fk_vet_specialties_specialties foreign key (specialty_id) references specialties(id); CREATE TABLE types ( id INTEGER NOT NULL IDENTITY PRIMARY KEY, name VARCHAR(80) ); CREATE INDEX types_name ON types(name); CREATE TABLE owners ( id INTEGER NOT NULL IDENTITY PRIMARY KEY, first_name VARCHAR(30), last_name VARCHAR(30), address VARCHAR(255), city VARCHAR(80), telephone VARCHAR(20) ); CREATE INDEX owners_last_name ON owners(last_name); CREATE TABLE pets ( id INTEGER NOT NULL IDENTITY PRIMARY KEY, name VARCHAR(30), birth_date DATE, type_id INTEGER NOT NULL, owner_id INTEGER NOT NULL ); alter table pets add constraint fk_pets_owners foreign key (owner_id) references owners(id); alter table pets add constraint fk_pets_types foreign key (type_id) references types(id); CREATE INDEX pets_name ON pets(name); CREATE TABLE visits ( id INTEGER NOT NULL IDENTITY PRIMARY KEY, pet_id INTEGER NOT NULL, visit_date DATE, description VARCHAR(255) ); alter table visits add constraint fk_visits_pets foreign key (pet_id) references pets(id); CREATE INDEX visits_pet_id ON visits(pet_id);
2. Create PopulateDB.sql script to bootstrap data into database. a. In the new directory, add populateDB.sql script to bootstrap the database:
--Modified by Mike Ashby: modified to work with Windows Azure SQL Database. --SQL Server requires Identity to be disabled when explicitly setting a column with Identity on. --Insert INTO statements in SQL Server require explicit columns. SET IDENTITY_INSERT vets ON; INSERT INTO vets (id, first_name, last_name) VALUES (1, 'James', 'Carter'); INSERT INTO vets (id, first_name, last_name) VALUES (2, 'Helen', 'Leary'); INSERT INTO vets (id, first_name, last_name) VALUES (3, 'Linda', 'Douglas'); INSERT INTO vets (id, first_name, last_name) VALUES (4, 'Rafael', 'Ortega'); INSERT INTO vets (id, first_name, last_name) VALUES (5, 'Henry', 'Stevens'); INSERT INTO vets (id, first_name, last_name) VALUES (6, 'Sharon', 'Jenkins'); SET IDENTITY_INSERT vets OFF;
Page 23
SET IDENTITY_INSERT specialties ON; INSERT INTO specialties (id, name) VALUES (1, 'radiology'); INSERT INTO specialties (id, name) VALUES (2, 'surgery'); INSERT INTO specialties (id, name) VALUES (3, 'dentistry'); SET IDENTITY_INSERT specialties OFF; INSERT INTO vet_specialties VALUES (2, 1); INSERT INTO vet_specialties VALUES (3, 2); INSERT INTO vet_specialties VALUES (3, 3); INSERT INTO vet_specialties VALUES (4, 2); INSERT INTO vet_specialties VALUES (5, 1); SET IDENTITY_INSERT types ON; INSERT INTO types (id, name) VALUES (1, 'cat'); INSERT INTO types (id, name) VALUES (2, 'dog'); INSERT INTO types (id, name) VALUES (3, 'lizard'); INSERT INTO types (id, name) VALUES (4, 'snake'); INSERT INTO types (id, name) VALUES (5, 'bird'); INSERT INTO types (id, name) VALUES (6, 'hamster'); SET IDENTITY_INSERT types OFF;
SET IDENTITY_INSERT owners ON; INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); INSERT INTO owners (id,first_name ,last_name ,address ,city ,telephone) VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); SET IDENTITY_INSERT owners OFF;
Page 24
SET IDENTITY_INSERT pets ON; INSERT INTO pets (id, name ,birth_date 1, 1); INSERT INTO pets (id, name ,birth_date 06', 6, 2); INSERT INTO pets (id, name ,birth_date 2, 3); INSERT INTO pets (id, name ,birth_date 07', 2, 3); INSERT INTO pets (id, name ,birth_date 3, 4); INSERT INTO pets (id, name ,birth_date 20', 4, 5); INSERT INTO pets (id, name ,birth_date 04', 1, 6); INSERT INTO pets (id, name ,birth_date 1, 6); INSERT INTO pets (id, name ,birth_date 06', 5, 7); INSERT INTO pets (id, name ,birth_date 02-24', 2, 8); INSERT INTO pets (id, name ,birth_date 09', 5, 9); INSERT INTO pets (id, name ,birth_date 24', 2, 10); INSERT INTO pets (id, name ,birth_date 1, 10); SET IDENTITY_INSERT pets OFF; SET IDENTITY_INSERT visits ON; INSERT INTO visits (id, pet_id 'rabies shot'); INSERT INTO visits (id, pet_id 'rabies shot'); INSERT INTO visits (id, pet_id 'neutered'); INSERT INTO visits (id, pet_id 'spayed'); SET IDENTITY_INSERT visits OFF;
,type_id ,type_id ,type_id ,type_id ,type_id ,type_id ,type_id ,type_id ,type_id ,type_id ,type_id ,type_id ,type_id
,owner_id) VALUES (1, 'Leo', '2000-09-07', ,owner_id) VALUES (2, 'Basil', '2002-08,owner_id) VALUES (3, 'Rosy', '2001-04-17', ,owner_id) VALUES (4, 'Jewel', '2000-03,owner_id) VALUES (5, 'Iggy', '2000-11-30', ,owner_id) VALUES (6, 'George', '2000-01,owner_id) VALUES (7, 'Samantha', '1995-09,owner_id) VALUES (8, 'Max', '1995-09-04', ,owner_id) VALUES (9, 'Lucky', '1999-08,owner_id) VALUES (10, 'Mulligan', '1997,owner_id) VALUES (11, 'Freddy', '2000-03,owner_id) VALUES (12, 'Lucky', '2000-06,owner_id) VALUES (13, 'Sly', '2002-06-08',
,description ) VALUES (1, 7, '1996-03-04', ,description ) VALUES (2, 8, '1996-03-04', ,description ) VALUES (3, 8, '1996-06-04', ,description ) VALUES (4, 7, '1996-09-04',
3. Go ahead and add the script for Logback (logging framework) a. In the new directory create, mssql.sql:
Page 25
-- Logback: the reliable, generic, fast and flexible logging framework. -- Copyright (C) 1999-2010, QOS.ch. All rights reserved. --- See http://logback.qos.ch/license.html for the applicable licensing -- conditions. -- This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender --- The event_id column type was recently changed from INT to DECIMAL(40) -- without testing. --Modified by Mike Ashby: modified to work with Windows Azure SQL Database. --reduced Decimal(40) to Decimal(38) which is SQL Servers max. CREATE TABLE logging_event ( timestamp DECIMAL(20) NOT NULL, formatted_message VARCHAR(4000) NOT NULL, logger_name VARCHAR(254) NOT NULL, level_string VARCHAR(254) NOT NULL, thread_name VARCHAR(254), reference_flag SMALLINT, arg0 VARCHAR(254), arg1 VARCHAR(254), arg2 VARCHAR(254), arg3 VARCHAR(254), caller_filename VARCHAR(254) NOT NULL, caller_class VARCHAR(254) NOT NULL, caller_method VARCHAR(254) NOT NULL, caller_line CHAR(4) NOT NULL, event_id DECIMAL(38) identity NOT NULL, PRIMARY KEY(event_id) ); CREATE TABLE logging_event_property ( event_id DECIMAL(38) NOT NULL, mapped_key VARCHAR(254) NOT NULL, mapped_value VARCHAR(1024), PRIMARY KEY(event_id, mapped_key), FOREIGN KEY (event_id) REFERENCES logging_event(event_id) ) CREATE TABLE logging_event_exception ( event_id DECIMAL(38) NOT NULL, i SMALLINT NOT NULL, trace_line VARCHAR(254) NOT NULL, PRIMARY KEY(event_id, i), FOREIGN KEY (event_id) REFERENCES logging_event(event_id) )
4. Modify JDBC properties a. In properties file at ~\src\main\resources\spring\data-access.properties b. Comment out HSQL section. c. Add new SQL Server section:
Page 26
#------------------------------------------------------------------------------# SQL Server Settingstcp:XXXXXXXX.database.windows.net;Initial Catalog=PetClinicDB;Persist Security Info=True;User ID=login@server;Password=*********** jdbc.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver jdbc.url=jdbc:sqlserver://server.database.windows.net:1433;databaseName=PetClinicDB jdbc.username=login@server jdbc.password=password # Properties that control the population of schema and data for a new data source jdbc.initLocation=classpath:db/mssqldb/initDB.sql jdbc.dataLocation=classpath:db/mssqldb/populateDB.sql jdbc.logdataLocation=classpath:db/mssqldb/mssql.sql # Property that determines which Hibernate dialect to use # (only applied with "applicationContext-hibernate.xml") hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect # Property that determines which JPA DatabasePlatform to use with TopLink Essentials jpa.databasePlatform=org.springframework.samples.petclinic.sqlserver.EssentialsSQLPlatformWithNativeSequence # Property that determines which database to use with an AbstractJpaVendorAdapter jpa.database=SQL_SERVER
To:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" p:testOnBorrow="True" p:testOnReturn="True" p:validationQuery="SELECT 1; />
6. Modify web.xml to enable Spring Data JPA a. Open ~\src\main\webapp\WEB-INF\web.xml b. Under <param-name>spring.profiles.active</param-name> c. Set the active profile to Spring-data-jpa: <param-value>spring-data-jpa</param-value>
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="false" scanPeriod="30 seconds" > <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> <resetJUL>true</resetJUL> </contextListener> <!-- To enable JMX Management --> <jmxConfigurator/> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%-5level %logger{0} - %msg%n</pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>C:/temp/LogFile.log</file> <append>true</append> <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <driverClass>com.microsoft.sqlserver.jdbc.SQLServerDriver</driverClass> <url>jdbc:sqlserver://Put_server_here.database.windows.net:1433;databaseName=Put_Database_Here</url> <user>Put_login_here@put_servername_here</user> <password>Put_Password_Here</password> </connectionSource> </appender> <logger name="org.hibernate" level="warn"> <appender-ref ref="console" /> </logger> <logger name="org.springframework.samples.petclinic" level="warn"> <appender-ref ref="DB" /> </logger>
Page 28
Warning: Writing logs to the DB can be time consuming and can delay Tomcat start up beyond its Start Timeout. In Spring Tool Suite the timeout can be increased finding and double clicking on Tomcat under Servers. Then click on Timeouts section and increase the Start timeout to something like 3 minutes.
Step 10: Inject Exception Handling for Transient Faults via AOP
Windows Azure SQL Database is a multi-tenant, high availability database implementation of Microsoft SQL Server 2012. Its HA and Internet-scale architecture requires that certain transient faults be captured and SQL commands retriedon these conditions. The database connections can be throttled internally by the SQL Database for several reasons, such as excessive resource usage, long-running transactions, and possible failover and load balancing actions, leading to termination of a client session or temporary inability to establish new connections while a transient condition persists. The database connections may also be dropped due to the variety of reasons related to Internet connectivity between the client and distant Microsoft data centers: quality of network, intermittent network faults in the clients LAN or WAN infrastructure and other transient technical reasons. For this reason we need to be able to intercept these errors, determine their severity, and then determine our course of action. Here we demonstrate how to intercept errors via AOP. 2. In the logback configuration, ~\src\main\resources\logback.xml a. Add a database appender, DBAppender b. Add a logger for the DBAppender
Page 29
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="false" scanPeriod="30 seconds" > <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> <resetJUL>true</resetJUL> </contextListener> <!-- To enable JMX Management --> <jmxConfigurator/> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%-5level %logger{0} - %msg%n</pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>C:/temp/LogFile.log</file> <append>true</append> <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <driverClass>com.microsoft.sqlserver.jdbc.SQLServerDriver</driverClass> <url>jdbc:sqlserver://Put_server_here.database.windows.net:1433;databaseName=Put_Database_Here</url> <user>Put_login_here@put_servername_here</user> <password>Put_Password_Here</password> </connectionSource> </appender> <logger name="org.hibernate" level="warn"> <appender-ref ref="console" /> </logger> <logger name="org.springframework.samples.petclinic" level="warn"> <appender-ref ref="DB" /> </logger>
Page 30
Warning: writing logs to the DB can be time consuming and can delay Tomcat start up beyond its Start Timeout. In Spring Tool Suite the timeout can be increased finding and double clicking on Tomcat under Servers. Then click on Timeouts section and increase the Start timeout to something like 3 minutes.
Step 11: Inject Exception Handling for Transient Faults via AOP
Windows Azure SQL Database services implements a throttling behavior which can throttle resources. For instance, when a client is establishing connections to a Windows Azure SQL Database or running queries against it. The database connections can be throttled internally by Windows Azure SQL Database for several reasons, such as excessive resource usage, long-running transactions, and possible failover and load balancing actions, leading to termination of a client session or temporary inability to establish new connections while a transient condition persists. The database connections may also be dropped due to the variety of reasons related to network connectivity between the client and distant Microsoft data centers: quality of network, intermittent network faults in the clients LAN or WAN infrastructure and other transient technical reasons. For this reason we need to be able to intercept these errors, determine their severity, and then determine our course of action. Here we demonstrate how to intercept errors via AOP. 1. Add new class file, ExceptionHandler.java at ~\src\main\java\org\springframework\samples\petclinic\service\ 2. To this file, add this code which will target two methods in the ClientServiceImpl:
Page 31
package org.springframework.samples.petclinic.service; import java.sql.SQLException; import java.util.Locale; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceAware; import org.springframework.stereotype.Component; @Aspect @Component public class ExceptionHandler { private MessageSource messageSource; @Pointcut("execution(* org.springframework.samples.petclinic.service.ClinicServiceImpl*.*(..))") public void findPetTypes() { } @Pointcut("execution(* org.springframework.samples.petclinic.service.ClinicServiceImpl*.*(..))") public void findOwnerById() { } @Around("findPetTypes() || findOwnerById()") public Object profile(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); System.out.println("Going to call method: " + pjp.getSignature()); Object output = pjp.proceed(); System.out.println("Method execution completed."); long elapsedTime = System.currentTimeMillis() - start; System.out.println("Method execution time: " + elapsedTime + " milliseconds."); //add your Transient Fault Exception Handling here // throw new SQLException(); return output; } }
3. AOP requires a default constructor, so we need to add one to ClinicServiceImpl. In ~\src\main\java\org\springframework\samples\petclinic\service\ClinicServiceImpl.java Add this constructor:
public ClinicServiceImpl(){}
Page 32
</dependency>
4. Add SSM to Tools Configuration a. Open ~\src\main\resources\spring\tools-config.xml b. Add: <import resource="simplesm-context.xml"/> c. And add the following beans:
<bean id="clinicServiceImpl" class="org.springframework.samples.petclinic.service.ClinicServiceImpl" /> <bean id="exceptionHandler" class="org.springframework.samples.petclinic.service.ExceptionHandler" /> Add SSM Memcached Client bean: <bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory"> <property name="cacheClientFactory"> <bean class="com.google.code.ssm.providers.spymemcached.MemcacheClientFactoryImpl" /> </property> <property name="addressProvider"> <bean class="com.google.code.ssm.config.DefaultAddressProvider"> <property name="address" value="localhost:11211" /> </bean> </property> <property name="configuration"> <bean class="com.google.code.ssm.providers.CacheConfiguration"> <property name="consistentHashing" value="true" /> </bean> </property> </bean>
5. Add SSM context XML file to path Simple Spring Memcached comes with a xml configuration file which can be found in the SSM project files. a. Add simplesm-context.xml to ~\src\main\resources\spring\ 6. Make objects to be cached serializable by altering base class. a. Open base entity class, and change BaseEntity to implement Serializable, ~\src\main\java\org\springframework\samples\petclinic\model\BaseEntity.java b. Open Person class and add SSMs CacheKeyMethod reference and annot ation import com.google.code.ssm.api.CacheKeyMethod; () @CacheKeyMethod public String getLastName() { c. Make Vets un-cached so we can add it to Memcached by commenting out @Cacheable in ~\src\main\java\org\springframework\samples\petclinic\repository\jpa\JpaVetRepositoryImpl.jav 7. Simple-Spring-Memcached requires that all methods it intercepts implement signatures a specific way. For instance, only List<> is allowed as a parameter for collection types and if they need @ParameterValueKeyProvider (which is used by single key provider types) then the type needs to be integer. See SSM documentation for more details. The following changes are required in ~\src\main\java\org\springframework\samples\petclinic\service\ClinicService.java public void saveOwner(Owner owner, int id) throws DataAccessException;
October 11, 2013 Page 33
List<Owner> findOwnerByLastName(List<String> lastName) In ~\src\main\java\org\springframework\samples\petclinic\service\ClinicServiceImpl.java this is where the meat of the implementation occurs. Notice that the changes we are making are to method signatures and annotations. There arent any functional changes required. New code in red:
@Transactional(readOnly = true, timeout = 60) @ReadThroughSingleCache( namespace="Owner", expiration = 300) public List<Owner> findOwnerByLastName(@ParameterValueKeyProvider List<String> lastName) throws DataAccessException { return (List<Owner>) ownerRepository.findByLastName( lastName.get(0)); } @Override @Transactional(readOnly = true, timeout = 60) @ReadThroughAssignCache(namespace="OwnersAll" , assignedKey ="0", expiration = 300) public List<Owner> findOwnerByLastName(String lastName) throws DataAccessException { return (List<Owner>) ownerRepository.findByLastName( lastName); } @Override @Transactional(timeout = 60) @InvalidateSingleCache(namespace = "Owner" ) @InvalidateAssignCache(namespace = "OwnersAll" , assignedKey ="0" ) public void saveOwner(Owner owner, @ParameterValueKeyProvider int id) throws DataAccessException { ownerRepository.save(owner); } @Override @Transactional(readOnly = true, timeout = 60) @ReadThroughSingleCache( namespace="Owner" , expiration = 300) public Owner findOwnerById(@ParameterValueKeyProvider int id) throws DataAccessException { return ownerRepository.findById(id); } @Override @Transactional(readOnly = true, timeout = 60) @ReadThroughAssignCache( namespace="Vets" , assignedKey ="0", expiration = 300) public Collection<Vet> findVets( ) throws DataAccessException { return vetRepository.findAll(); }
In ~\src\main\java\org\springframework\samples\petclinic\web\OwnerController.java mostly simple signature changes required by SSM. But the biggest code change also occurs here. We had to add logic because SSM doesnt handle the situation where a parameter is null. So we had to create a new findOwnerByLastName with a new signature that could be used with an AssignCache annotation. Note: These are limitations of SSM not Azure. We only use the AssignCache when the parameter is null/empty. This happens when the user searches for all pet owners and leaves the search field blanks.
Page 34
Collection<Owner> results; if(owner.getLastName().trim().isEmpty()) { results = this.clinicService.findOwnerByLastName( owner.getLastName()); } else{ List<String> param = new ArrayList<String>(); param.add( owner.getLastName()); results = this.clinicService.findOwnerByLastName( param); }
With that we conclude coverage of the code changes required to add Windows Azure SQL Database, Memcached, and Transient Fault Exception Handling to the Spring Framework Pet Clinic Demo. In the following sections we describe how to package and deploy Pet Clinic to Azure Compute.
Page 35
VIII. Windows Azure Java Application Lifecycle: Creating a New Azure Deployment Project
Now you are ready to start deploying to Window Azure Compute. Before we can deploy to Windows Azure, we must create an Azure Deployment Project. On a high level, the steps to create a deployment project are as follows: 1. 2. 3. 4. --Export the WAR file Create a Windows Azure Deployment Project Deploy to the local Windows Azure Compute emulator Publish to the Windows Azure cloud
3. Select your web project and then select the destination area, as the place in which you are maintaining your source code. 4. Set Target Runtime to Apache 7.0.
Page 36
5. Click Finish.
2. A new deployment project wizard window opens. Name your project and then click Next. a. Note: Your project name must be unique from what you have named your source-code file directory.
3. Hit Next, then select the latest JDK, (which you have already downloaded).
Page 37
4. Hit Next, then select the application server. Select Apache Tomcat 7.
Page 38
Note: The Tomcat directory here is not the path to your local Tomcat instance. Instead, it is a path to the Tomcat extracted files from a zip file. Import WAR File 5. Hit Next, under Application, click Add. The Add Application window will open. Click Browse and then point to the Pet Clinic sample application which if you followed steps from above is named ROOT.war which is a reserved name in Tomcat for the root app. Click OK and your web application will be included in the list of applications.
6. Click Finish. 7. Open the new deployment project, PetClinicAzureDeployment 8. Notice the WorkerRole1 that was created. Right mouse click on it, select Windows Azure -> properties. You should see this:
Page 39
9. Increase numbers of instances as appropriate. This will set an initial deployment count. This can be increased or decreased from web service calls or the Windows Azure Portal UI later after deployment. Note: a minimum of 2 is required for high availability option in Caching. 10. Select Caching
a. Click on Enable co-located caching to use all the compute instances in the deployment as cache servers. b. Since we have more than one instance, select High Availability to Yes. c. NOTE: the Host name is localhost_workerrole1, make sure the SSM address provider in toolsconfig.xml is set like:
<property name="addressProvider"> <bean class="com.google.code.ssm.config.DefaultAddressProvider"> <property name="address" value="localhost_WorkerRole1:11211" /> </bean>
If not, then fix this and re-export your war file. As long as you deploy the war file to the same location the Azure Deployment Project will pick up the new war during build. d. Right click on the PetClinicAzureDeploymentProject again. Bring up Windows Azure Properties. Click on Subscriptions.
Page 40
e. If no account settings have previously been downloaded click in Import from PUBLISH -SETTINGS File
f. Click on Download PUBLISH-SETTINGS File, you will be connected to the Windows Azure portal. g. After logging into the portal, a download of your account settings will start automatically. Save the file with your project. h. Now click Browse on the Import Subscription Information window, and import the file downloaded. i. Now you can select the storage account from the drop down list. j. Click Ok.
Page 41
Page 42
2. The Publish Wizard will appear, import your Azure settings you downloaded in when we deployed to emulator. This will import all your subscription information. 3. If you dont have an existing storage account you can create a new storage account for your deployment by clicking New next to Storage Account. In the New Storage Account window, provide a unique name and access key. 4. Create a new Cloud Service by clicking on New next to Service Name. In the New Cloud Service window, provide a unique name and location. 5. Set Target environment to Production
Page 43
6. Click Publish and watch the progress in Eclipse (STS). A typical deployment can take a few minutes.
In this example, since the service name is petclinic the URL in Windows Azure will be:
Page 44
Page 45