Getting started with Continuous Integration for SOA projects

This post is part of a series on Continuous Integration.

I am exploring how to use Maven and Hudson to create a continuous integration capability for SOA and BPM projects.  This will be the first post of several on this topic, and today we will look at setting up some simple continuous integration for a single SOA project.  In future posts I will expand on this and look at BPM, Human Task user interface projects, ADF, etc., but you have to start somewhere!

Before we start, let’s take a look at an overview of what we are trying to achieve and how we plan to do it.

Our goal is to be able to check a SOA project (that’s project, not application) from JDeveloper into our source code control system (Subversion) and have it automatically compiled, packaged and deployed to our test SOA server.  If anything goes wrong, we want an email to let us know what happened.

Here are the components we will be using.  Blue boxes are on the test/development server, green on the developer’s machine.

We will be using Hudson as our continuous integration server.  I used Hudson 1.396 running on WebLogic Server 10.3.4, as described in this post.

We will have Hudson run a Maven job.  Strictly speaking this is probably a little bit of overkill for this example, but as I am planning to build up this environment to handle other types of projects (BPM, WebCenter, ADF, Java EE, etc.) and to handle applications with multiple projects in them, having Maven in the picture is a good idea – it will make things easier for me later on.  Plus, I like it.  I used Maven 2.2.1.

We will have Maven run the ANT jobs that are included with Oracle SOA Suite 11g.  I used SOA Suite 11.1.1.4.

We also need version control.  I used Subversion 1.6.11.  Hudson will monitor the Subversion repository and when it sees a change, it will perform a build (compile, package and deploy the composite).

I have all of the server components running on Oracle Linux 5.5, everything is 64-bit.

My client is Windows 7 (also 64-bit) and I am running JDeveloper 11.1.1.4 with the SOA Composite Editor plugin installed.  JDeveloper includes support for Subversion ‘out of the box.’

In JDeveloper, we create an Application to hold our Project(s).  There can be one or more projects in an application.  There can also be none, but that would not be very useful.  Within the project, we are going to create a Maven POM so that Maven (and therefore Hudson) knows how to build our composite project.

First, let’s take a look at the ANT jobs we will use.  These are found in the SOA Suite installation under the Oracle_SOA1/bin directory:

ant-sca-compile.xml       Compiles a composite project
ant-sca-package.xml       Packages a composite project (into a SAR)
ant-sca-deploy.xml        Deploys a composite project (a SAR)

We can use these scripts to compile, package and deploy our project.  Each script needs some variables/properties/arguments to tell it what to do:

ant-sca-compile.xml, target: scac
  scac.input:             The location of the composite.xml

ant-sca-package.xml, target: package
  compositeName:          The name of the composite (will show up in EM)
  compositeDir:           The directory containing the composite
  revision:               The version number for the composite

ant-sca-deploy.xml, target: deploy
  serverURL:              The URL of the SOA instance
  user:                   The user to do the deployment
  password:               The deploying user's password
  sarLocation:            The location of the SAR file
  overwrite:              Overwrite existing deployments with same revision?
  forceDefault:           Make this version the default version?
  partition:              Which SOA partition to deploy into

Here is the POM file that we can add into our project, you can just go ahead and create it in JDeveloper, in the root directory of your project, the same place where the composite.xml is located.  It should be called pom.xml.  Here is the complete file.  Following the file, we will walk through the various sections:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>soaProject2</groupId>
  <artifactId>soaProject2</artifactId>
  <version>1.0-SNAPSHOT</version>

  <scm>
    <connection>scm:svn:svn+ssh://mark@ofm1.au.oracle.com/home/mark/svnrepos/soaProject2/trunk</connection>
    <developerConnection>scm:svn:svn+ssh://mark@ofm1.au.oracle.com/home/mark/svnrepos/soaProject2/trunk</developerConnection>
  </scm>

  <dependencies>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.6</version>
        <executions>
          <execution>
            <id>sca-compile</id>
            <phase>compile</phase>
            <configuration>
              <target>
                <property name="scac.input" value="${basedir}/composite.xml" />
                <ant antfile="/home/mark/Oracle/Middleware/Oracle_SOA1/bin/ant-sca-compile.xml"
                     dir="/home/mark/Oracle/Middleware/Oracle_SOA1/bin"
                     target="scac" />
              </target>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
          <execution>
            <id>sca-package</id>
            <phase>package</phase>
            <configuration>
              <target>
                <property name="build.compiler" value="extJavac"/>
                <property name="compositeName" value="${project.artifactId}" />
                <property name="compositeDir" value="${basedir}" />
                <property name="revision" value="${project.version}" />
                <ant antfile="/home/mark/Oracle/Middleware/Oracle_SOA1/bin/ant-sca-package.xml"
                     dir="/home/mark/Oracle/Middleware/Oracle_SOA1/bin"
                     target="package" />
              </target>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
          <execution>
            <id>sca-deploy</id>
            <phase>deploy</phase>
            <configuration>
              <target>
                <property name="serverURL" value="http://ofm1.au.oracle.com:8001" />
                <property name="user" value="weblogic" />
                <property name="password" value="Fusion11g" />
                <property name="sarLocation" value="${basedir}/deploy/sca_${project.artifactId}_rev${project.version}.jar" />
                <property name="overwrite" value="true" />
                <property name="forceDefault" value="true" />
                <property name="partition" value="default" />
                <ant antfile="/home/mark/Oracle/Middleware/Oracle_SOA1/bin/ant-sca-deploy.xml"
                     dir="/home/mark/Oracle/Middleware/Oracle_SOA1/bin"
                     target="deploy" />
              </target>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <distributionManagement>
    <!-- use the following if you're not using a snapshot version. -->
    <repository>
      <id>local</id>
      <name>local repository</name>
      <url>file:///home/mark/.m2/repository</url>
    </repository>
    <!-- use the following if you ARE using a snapshot version. -->
    <snapshotRepository>
      <id>localSnapshot</id>
      <name>local snapshot repository</name>
      <url>file:///home/mark/.m2/repository</url>
    </snapshotRepository>
  </distributionManagement>

</project>

First, we have the Maven coordinates that will identify this project.  You might want to make the groupId the name of your application and the artifactId the name of your project.  Or you might want to come up with a better groupId :-)  Later, we will use these to produce the name of the composite and the SAR deployment archive.

  <groupId>soaProject2</groupId>
  <artifactId>soaProject2</artifactId>
  <version>1.0-SNAPSHOT</version>

Next we have the details for our Subversion server.  JDeveloper will also need to be told these details independently of this.  Maven will use the details here in the POM if we want to do a ‘release’ in Maven.  The distributionManagement section (see above) is also provided for this purpose and so that Maven can archive our builds during deployment.

  <scm>
    <connection>scm:svn:svn+ssh://mark@ofm1.au.oracle.com/home/mark/svnrepos/soaProject2/trunk</connection>
    <developerConnection>scm:svn:svn+ssh://mark@ofm1.au.oracle.com/home/mark/svnrepos/soaProject2/trunk</developerConnection>
  </scm>

We are going to use the maven-antrun-plugin to execute the ANT tasks.  You can see the configuration in the complete POM above.  We will include the three separate ANT jobs (compile, package and deploy) in three phases of our Maven build.  Basically, we create an execution, give it an id, assign it to a phase, and then we add inside the target section our property‘s and then run the ant task giving it the antfile, a directory to run in, and a target to run.  Here is the relevant section for the compile:

          <execution>
            <id>sca-compile</id>
            <phase>compile</phase>
            <configuration>
              <target>
                <property name="scac.input" value="${basedir}/composite.xml" />
                <ant antfile="/home/mark/Oracle/Middleware/Oracle_SOA1/bin/ant-sca-compile.xml"
                     dir="/home/mark/Oracle/Middleware/Oracle_SOA1/bin"
                     target="scac" />
              </target>

You can see the full POM above.  One little trick to be aware of is that we need to add an extra property to the package phase to make sure it uses the external JDK.  If you don’t include this property, you will most likely get an error telling you ANT cannot find javac because it is pointing to a JRE, not a JDK.

                <property name="build.compiler" value="extJavac"/>

Having adding this file to your project, you now need to check the project into Subversion. First we need to create a repository connection (if you don’t already have one.)  To do this, go to the View menu, then the Team submenu, and select Versioning Navigator.  Right click on the Subversion icon and select New Repository Connection…

Add the details as per the example below, and click on the Test Read Access button to make sure you can connect to the repository.

Now we can add (import) our project into Subversion.  This is done by selecting Version Application… from the Versioning menu.  This will open the Import to Subversion wizard.

Click Next to move to the Destination page.  Select the repository connection you just created, then highlight the root node, and click on the little folder icon on the top right of the path hierarchy tree display to create a new directory on the Subversion repository.  I created one called soaTest2.  You should probably get some guidance from the repository administrator if this is a shared repository.  I then highlighted that new directory and made another directory inside that called trunk, to follow the Subversion convention.

Now we select the correct directory to put our project in, i.e. the one we just created, root/soatest2/trunk in my case, and click on Next.

Here we check the Source Directory is correct (it should be fine) and then add your comments for the check in.  Then keep on clicking on Next until you get to the end of the wizard and then click on Finish.

This will add (import) your project into Subversion and then check it out into JDeveloper.  You can see the Subversion output in the SVN Console – Log pane at the bottom.  You will also notice that now you see the revision numbers after the names of the files in the Application Navigator pane.

Configuring Hudson

Now you need to create a job in Hudson (this is a one off activity, we will use this same job over and over again, each time we want to build and deploy this project.)

In the Hudson console, click on New Job.  Enter a name for the job, I called mine soaTest2.  Select the option to Build a Maven 2/3 project and click on OK.

On the next screen, we need to enter details for the job.  Select Subversion as the Source Code Management option, and then enter the Subversion repository URL.  Note that it will most likely be different now as Hudson is running on the same development server as Subversion (at least in my case it is).  So for me, I used the file:/// URL, not the svn+ssh:// one.  Because of the way JDeveloper does its checkin, you will want to put the project name on the end of the URL too.  In my case, the URL is:

file:///home/mark/svnrepos/soaTest2/trunk/soaTest2

Scroll down and select the Poll SCM option, and enter * * * * * (that’s asterisk space asterisk space asterisk space asterisk space asterisk) in the Schedule field.  This tells Hudson to check every minute if Subversion has been updated.  Once you have done playing and see everything works, you might want to change this to something a bit less frequent.  It uses the same format as cron.

You can also set up email notifications as shown below.

A little further down, you can select the option to Deploy artifacts to the Maven repository (if you want to) and provide the URL for your Maven repository (again, from the server’s point of view.)

Now you can click on Save and then wait for a minute or so until Hudson checks for updates in Subversion.  When it does, it will notice your check in from JDeveloper and start a build.  If you click on the ENABLE AUTO REFRESH option in the top right corner you will see the build running on the Hudson dashboard.  Once it is done (or while it is still running if you like) you can click on the build number (it should be #1) and then click on the Console Output link to see the build output.

Here is my complete output, so you can compare:

tarted by user weblogic
Checking out a fresh workspace because the workspace is not file:///home/mark/svnrepos/soaTest2/trunk/soaTest2
Checking out file:///home/mark/svnrepos/soaTest2/trunk/soaTest2
A         composite.xml
A         xsl
A         SCA-INF
A         SCA-INF/src
A         SCA-INF/lib
A         pom.xml
A         soaTest2.jpr
A         xsd
A         testsuites
A         testsuites/fileList.xml
At revision 64
no revision recorded for file:///home/mark/svnrepos/soaTest2/trunk/soaTest2 in the previous build
Found mavenVersion 2.2.1 from file jar:file:/home/mark/apache-maven-2.2.1/lib/maven-2.2.1-uber.jar!/META-INF/maven/org.apache.maven/maven-core/pom.properties
Parsing POMs
Discovered a new module soaProject2:soaProject2 soaProject2
[workspace] $ /usr/java/jdk1.6.0_21/bin/java -Xmx2048m -cp /home/mark/.hudson/plugins/maven-plugin/WEB-INF/lib/maven-agent-1.396.jar:/home/mark/apache-maven-2.2.1/boot/classworlds-1.1.jar hudson.maven.agent.Main /home/mark/apache-maven-2.2.1 /home/mark/Oracle/Middleware/user_projects/domains/base_domain/servers/soa_server1/tmp/_WL_user/hudson/c97g3y/war/WEB-INF/lib/hudson-remoting-1.396.jar /home/mark/.hudson/plugins/maven-plugin/WEB-INF/lib/maven-interceptor-1.396.jar 9430 /home/mark/.hudson/plugins/maven-plugin/WEB-INF/lib/maven2.1-interceptor-1.2.jar
<===[HUDSON REMOTING CAPACITY]===>���channel started
Executing Maven:  -B -f /home/mark/.hudson/jobs/soaTest2/workspace/pom.xml deploy
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Unnamed - soaProject2:soaProject2:jar:1.0-SNAPSHOT
[INFO]    task-segment: [deploy]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources {execution: default-resources}] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /home/mark/.hudson/jobs/soaTest2/workspace/src/main/resources
[INFO] [compiler:compile {execution: default-compile}] [INFO] No sources to compile
[INFO] [antrun:run {execution: sca-compile}] [INFO] Executing tasks

main:

scac:
Validating composite "/home/mark/.hudson/jobs/soaTest2/workspace/composite.xml"
[INFO] Executed tasks
[INFO] [resources:testResources {execution: default-testResources}] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /home/mark/.hudson/jobs/soaTest2/workspace/src/test/resources
[INFO] [compiler:testCompile {execution: default-testCompile}] [INFO] No sources to compile
[INFO] [surefire:test {execution: default-test}] [INFO] No tests to run.
[HUDSON] Recording test results
[INFO] [jar:jar {execution: default-jar}] [WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: /home/mark/.hudson/jobs/soaTest2/workspace/target/soaProject2-1.0-SNAPSHOT.jar
[INFO] [antrun:run {execution: sca-package}] [INFO] Executing tasks

main:
     [echo] oracle.home = /home/mark/Oracle/Middleware/Oracle_SOA1/bin/..
    [input] skipping input as property compositeDir has already been set.
    [input] skipping input as property compositeName has already been set.
    [input] skipping input as property revision has already been set.

clean:
     [echo] deleting /home/mark/.hudson/jobs/soaTest2/workspace/deploy/sca_soaProject2_rev1.0-SNAPSHOT.jar

init:
    [mkdir] Created dir: /home/mark/.hudson/jobs/soaTest2/workspace/deploy

scac-validate:
     [echo] Running scac-validate in /home/mark/.hudson/jobs/soaTest2/workspace/composite.xml
     [echo] oracle.home = /home/mark/Oracle/Middleware/Oracle_SOA1/bin/..
    [input] skipping input as property compositeDir has already been set.
    [input] skipping input as property compositeName has already been set.
    [input] skipping input as property revision has already been set.

scac:
Validating composite "/home/mark/.hudson/jobs/soaTest2/workspace/composite.xml"

package:
     [echo] oracle.home = /home/mark/Oracle/Middleware/Oracle_SOA1/bin/..
    [input] skipping input as property compositeDir has already been set.
    [input] skipping input as property compositeName has already been set.
    [input] skipping input as property revision has already been set.

compile-source:
    [mkdir] Created dir: /home/mark/.hudson/jobs/soaTest2/workspace/dist
     [copy] Copying 6 files to /home/mark/.hudson/jobs/soaTest2/workspace/dist
     [copy] Warning: /home/mark/.hudson/jobs/soaTest2/.adf does not exist.
     [copy] Warning: /home/mark/.hudson/jobs/soaTest2/src does not exist.
     [copy] Warning: /home/mark/.hudson/jobs/soaTest2/workspace/src does not exist.
      [jar] Building jar: /home/mark/.hudson/jobs/soaTest2/workspace/deploy/sca_soaProject2_rev1.0-SNAPSHOT.jar
   [delete] Deleting directory /home/mark/.hudson/jobs/soaTest2/workspace/dist
[INFO] Executed tasks
[INFO] [install:install {execution: default-install}] [INFO] Installing /home/mark/.hudson/jobs/soaTest2/workspace/target/soaProject2-1.0-SNAPSHOT.jar to /home/mark/.m2/repository/soaProject2/soaProject2/1.0-SNAPSHOT/soaProject2-1.0-SNAPSHOT.jar
[INFO] [deploy:deploy {execution: default-deploy}] [INFO] Retrieving previous build number from localSnapshot
Uploading: file:///home/mark/.m2/repository/soaProject2/soaProject2/1.0-SNAPSHOT/soaProject2-1.0-20110315.093639-9.jar
2K uploaded  (soaProject2-1.0-20110315.093639-9.jar)
[INFO] Retrieving previous metadata from localSnapshot
[INFO] Uploading repository metadata for: 'snapshot soaProject2:soaProject2:1.0-SNAPSHOT'
[INFO] Retrieving previous metadata from localSnapshot
[INFO] Uploading repository metadata for: 'artifact soaProject2:soaProject2'
[INFO] Uploading project information for soaProject2 1.0-20110315.093639-9
[INFO] [antrun:run {execution: sca-deploy}] [INFO] Executing tasks

main:
     [echo] oracle.home = /home/mark/Oracle/Middleware/Oracle_SOA1/bin/..

deploy:
    [input] skipping input as property serverURL has already been set.
    [input] skipping input as property sarLocation has already been set.
setting user/password..., user=weblogic
Processing sar=/home/mark/.hudson/jobs/soaTest2/workspace/deploy/sca_soaProject2_rev1.0-SNAPSHOT.jar
Adding sar file - /home/mark/.hudson/jobs/soaTest2/workspace/deploy/sca_soaProject2_rev1.0-SNAPSHOT.jar
INFO: Creating HTTP connection to host:ofm1.au.oracle.com, port:8001
INFO: Received HTTP response from the server, response code=200
---->Deploying composite success.
[INFO] Executed tasks
[HUDSON] Archiving /home/mark/.hudson/jobs/soaTest2/workspace/pom.xml to /home/mark/.hudson/jobs/soaTest2/modules/soaProject2$soaProject2/builds/2011-03-15_20-36-22/archive/soaProject2/soaProject2/1.0-SNAPSHOT/pom.xml
[HUDSON] Archiving /home/mark/.hudson/jobs/soaTest2/workspace/target/soaProject2-1.0-SNAPSHOT.jar to /home/mark/.hudson/jobs/soaTest2/modules/soaProject2$soaProject2/builds/2011-03-15_20-36-22/archive/soaProject2/soaProject2/1.0-20110315.093639-9/soaProject2-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 14 seconds
[INFO] Finished at: Tue Mar 15 20:36:42 EST 2011
[INFO] Final Memory: 34M/438M
[INFO] ------------------------------------------------------------------------
channel stopped
Deploying artifacts to file:///home/mark/.m2/repository
Deploying the main artifact soaProject2-1.0-SNAPSHOT.jar
Sending e-mails to: somebody@someplace.com
Finished: SUCCESS

You can see that each of the ANT jobs was run in turn, the compile, package and then deploy.  You can now go and logon to Enterprise Manager on your SOA server and you will see your composite is deployed.

Well that completes our basic setup for getting started with continuous integration in a SOA environment.  We will be writing more soon.  For now, enjoy!

About Mark Nelson

Mark Nelson is an Architect ("IC6") in the Platform Architecture Team in Oracle Development. Mark's focus area is continuous delivery, configuration management and provisioning - making it simple to manage the configuration of complex environments and applications built with Oracle Database, Fusion Middleware and Fusion Applications, on-premise and in the cloud. Before joining the Platform Architecture team, Mark was a senior member of the A-Team since 2010, and worked in Sales Consulting at Oracle since 2006 and various roles at IBM since 1994.
This entry was posted in Uncategorized and tagged , , , , , , . Bookmark the permalink.

13 Responses to Getting started with Continuous Integration for SOA projects

  1. Pingback: Extending Continuous Integration to include MDS-dependent components | RedStack

  2. Hi Mark,

    This is really nice article. thanks for putting this up.

    In my setup, everything working fine , but it’s not executing last step of deployment.(sca-deploy).
    i used exact pom.xml as you outlined above and did env specific changes.

    Checkout is happening and after that project gets compiled and also getting packaged properly. I can see packaged jar as well. But after that it’s no calling sca-deploy and says “BUILD is successful”. Am i missing something ?

    Advanced thanks for your time and reply.

    Thanks,
    Satish

  3. Dwight Looye says:

    Hi did you tell that the goal to achieve is deploy??

    I missed that one at the build / pom part! After that the deployment was done!

    • Mark Nelson says:

      When you issue the mvn (maven) command, you tell it what phase/goal to acheive – e.g. ‘mvn deploy’ will run all the phases up to and including ‘deploy.’
      In the POM file you can map a goal to any phase – as you might do when writing your own plugin for example.

  4. Mark,

    Thanks for the excellent post…
    I am facing a issue where i am do not have option to create Maven 2/3 Job type, am i missing any configuration?

    Regards,
    Ravi

    • Mark Nelson says:

      Yeah I think in the newer version of Hudson this option has been removed. You need to use the freestyle project type instead. In there you can point it to Maven.

  5. oraclesoa11 says:

    Mark, Thanks for the article. I have a dependency related question. If you consider the scenario of application1 having two projects proj1 and proj2 and proj2 is dependent on proj1. Lets assume developer has a local weblogic soa env on his machine (green box) in which he deployed and tested the application before checking in the changes. Naturally some of the wsdl location references in proj2 will have localhost for hostname in the files that were checked into SVN. Now when Hudson kicks off a Maven build on the unix machine, the compilation of proj2 should fail since the needed wsdl cannot be found at localhost. I know that using configuration plans which get applied only during deploy task one can deploy to various env without issues. But how to compile successfully in this scenario?

    • Mark Nelson says:

      I would encourage you to store those in MDS so that the URL will not change from environment to environment.

  6. rkirkov says:

    Hi Mark,
    it’s really helpful article, thanks for that. Just wanted to share with you that we had a small issue. The jar file that was published to the repository was almost empty (most of the files were missing). The reason was that the jar was taken from target folder (generated from maven) instead of the release folder (generated from ant-sca-package.xlm). The workaround that we used was to copy the jar from the release folder to the target folder after the execution of sca-package. E.g.:

    Best Regards
    Rado

    • Mark Nelson says:

      Thanks, that issue has been pointed out to me before. I am going to post an update soon that uses the same approach that you mentioned.

  7. nicehobbit says:

    Hi!
    I’m having some troubles in generating de sar file. I’ve tried to generate it with the ant-sca-package and it differed from the one generated from the IDE using the Deploy( generate sar file) option.

    The one generated with the IDE has a higher size and also it auto-excludes some folders. It also has a modified composite.xml :S

    I have read the documentation and it’s supposed that you can generate the sar file using the target package from the ant-sca-package but I can’t replicate that.

    Any help or comment will be appreciated.

    Thank you for such an useful article!

  8. lideresjava says:

    thanks for the excellent post, I want to know the purpose or the advantage of using maven, if the ant scripts provided by Oracle are responsible for the compilation. in the example the soa project doesn’t use any library from a maven repository (i think this will be hard or
    tedious to do with oracle soa)

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s