Last time we created a simple photo management web application in Rails, using a JRuby environment, and ran it on a local server. In this blog we will show you how to port it to run on top of SAP NetWeaver Cloud as a production environment. The application will make use of several NW Cloud services that will power its functionality. This tutorial could generally serve as a NW Cloud migration guide for other Rails applications as well. The first part if the series is a good preparation for our cloud journey here but is not mandatory for understanding this guide.
What is going to change
In general, the business logic and the UI of our application will stay the same. We will focus on the back-end resources that the app uses.
In the local development scenario the photos that we upload are stored directly on the file system. We could run that on NetWeaver Cloud as well, but in a cloud environment this is certainly not a good design. We need a reliable storage solution which will be 24/7 available and will prevent our pictures from being lost, in case the application VM crashes and is replaced with a new one by the NW Cloud infrastructure. For this purpose we are going to use the Document Service in SAP NetWeaver Cloud.
Furthermore, we have a relational database usage for our ActiveRecord models, powered by an SQLite3 database file, which lives again on the file system. For the same reasons this is not acceptable and needs a replacement. We will use the Persistence Service in NW Cloud for this functionality: it provides with relational database storage, powered by the MaxDB platform and offered by JDBC and JPA entry points.
Basically we will start with the application as we left it last time - the sources are in our project's GitHub repo, in the local branch. The changed application sources that this tutorial will produce at the end are available there as well, in the no-dest branch (the reasons for this strange name are historical). If you get something unclear here you can alway reach out to it as a reference, or better ask us.
We will need some additional gems for flying our application on SAP NetWeaver Cloud. To use the persistence service of NW Cloud our application needs MaxDB support for ActiveRecord. So let's install those two gems: jdbc-maxdb and activerecord-maxdb-adapter (if you don't have a Git installation, you can download the ZIPped repositories from GitHub directly):
jruby -S gem build jdbc-maxdb.gemspec jruby -S gem install jdbc-maxdb
jruby -S gem build activerecord-maxdb-adapter.gemspec jruby -S gem install activerecord-maxdb-adapter
Our app will need a different Gemfile for the production environment, so we use this one and run Bundler against it:
jruby -S bundle update
It will install the Warbler gem that will transform our Rails app into a WAR archive, suitable for running on NW Cloud. We create a Warbler configuration:
jruby -S bundle exec warble config
Using the ECM service for storing our photos will be achieved with the help of a tiny adapter layer, written in Java. You can find it in the cmis_client folder. Let's go through the steps needed to incorporate it into our application. You will see that those steps are generic enough to be reused by other applications, possibly at the price of small modifications.
In essence, we are going to use our own ECM repository. The parameters for this usage that you can adjust to your preference are repository key, repository unique name and user name. You can find them in the CMISProxyServlet and CmisClient classes.
File system storage is not longer our choice, so we delete the uploaded folder. First we have to compile the Java classes in this adapter layer. For that we have to download locally SAP NetWeaver Cloud SDK from here, and supply the file system path to it (after getting unzipped) inside the compile.rb helper script. Next, we execute the compilation:
mkdir classes jruby compile.rb
We put the CmisClient class in a separate jar:
cd classes jar -cf cmis_client.jar cmis/client/*.*
And finally we have to produce our WAR. But first, we will need to pre-compile application's assets so that they make it into the WAR and are thus available in the production environment. This will take some time, so be patient (we must make sure that the production environment here still points to SQLite3, as opposed to the GitHub file which is already gone through the tutorial):
jruby -S rake assets:precompile jruby -S bundle exec warble
This will generate the WAR file, including the web.xml descriptor inside. Please add the generated cmis_client.jar in WEB-INF/lib folder of the WAR, and the compiled CMISProxyServlet class in WEB-INF/classes, including all of its package-subfolders, that is, the com/sap/photo/app/CMISProxyServlet.class. In our case we have added some lines in the config/warble.rb configuration file to ask Warbler to do that for us automatically.
The next part comes a little bit boring, although its just a copy-paste-edit exercise: we incorporate the changes described in the photoapp/web.xml-instructions file into our web.xml descriptor: declaring the CMISProxyServlet and its mapping, modifying the URL mapping for the RackFilter, and adding the security section. It's a good idea to keep this web.xml because we'll need it later.
We configure our config/database.yml file to use the MaxDB adapter for NetWeaver Cloud:
production: adapter: maxdb encoding: utf8 reconnect: false jndi: java:comp/env/jdbc/DefaultDB pool: 5
and add in the config/warble.rb file this JNDI reference:
config.webxml.jndi = 'jdbc/DefaultDB'
In order to be able to execute our database migrations in NW Cloud environment, we instruct Warbler to include them in the WAR package that it produces, by adding the db folder in the following line in config/warble.rb (note that the public folder is included as well: it's there for the pre-compiled assets):
config.dirs = %w(app config lib db log vendor public tmp public)
and we add to our application a new initializer jpaas_db_migrate.rb in the config/initializers folder.
Finally, we prefix our table names as adding the following line in config/application.rb, which is needed because of MaxDB specifics:
config.active_record.table_name_prefix = 'r'
And if you suspect that we now have to warble our app again in order to incorporate those changes, you are right: we run it again, and we must be careful to not forget the changes from the previous section: packaging the proxy servlet, the cmis_client jar and modifying the web.xml
Adapting the application to the changes
We apply some changes in order to adapt the application to the ECM usage (the database level switch is transparent to the app and does not require any modifications): take a look at how the cmis client is being consumed from the Photo model, controller and view.
Running the application on the cloud
That was it! We are now ready to fasten our seat belts and take off! Let's deploy the application:
and start it. We access the app in the browser again at the known addresses https://photoappi055691trial.hanatrial.ondemand.com/photoapp/albums and https://photoappi055691trial.hanatrial.ondemand.com/photoapp/photos, to see for ourselves that storing fruits in the cloud has never been easier:
The last part of these blogs will show you usage of Connectivity Service and will present with some details about the Rails integration, for those who are interested about how all this really works.