<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Wandering Data</title>
	
	<link>http://iablog.sybase.com/mobiledatabase</link>
	<description>A blog about SQL Anywhere technologies for mobile applications</description>
	<lastBuildDate>Mon, 22 Aug 2011 19:21:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/WanderingData" /><feedburner:info uri="wanderingdata" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>A SQL Anywhere Push Sample for Android</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/Mj4Cofb2RgQ/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2011/08/a-sql-anywhere-push-sample-for-android/#comments</comments>
		<pubDate>Mon, 22 Aug 2011 19:21:06 +0000</pubDate>
		<dc:creator>Tom Slee, Senior Product Manager</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/2011/08/a-sql-anywhere-push-sample-for-android/</guid>
		<description><![CDATA[This sample uses the Google Cloud to Device Messaging Framework (C2DM) to push data changes from a SQL Anywhere database running on your desktop to an Android application. It shows you how to add push capability to your own SQL Anywhere application on Android. Preparation To get this sample to work, you first need to [...]]]></description>
			<content:encoded><![CDATA[<p>This sample uses the Google <em>Cloud to Device Messaging Framework</em> (<a href="http://code.google.com/android/c2dm">C2DM</a>) to push data changes from a SQL Anywhere database running on your desktop to an Android application. It shows you how to add push capability to your own SQL Anywhere application on Android.
</p>
<p><strong>Preparation<br />
</strong></p>
<p>To get this sample to work, you first need to register for two services. Each of these services needs to recognize your application, and see that is different from anyone else who has downloaded and is using this sample, so the registration needs to be done by you rather than by Sybase.
</p>
<ul>
<li>Sybase Hosted Relay Server. The relay server lets Android phones on public networks connect to a MobiLink server on your machine, even if there are firewalls between. You can register <a href="http://relayserver.sybase.com/account">here</a>; some instructions are <a href="http://iablog.sybase.com/mobiledatabase/2008/10/synchronizing-through-the-sql-anywhere-relay-server/">here</a>.
</li>
<li>Google C2DM. C2DM is the push service for Android. You can register <a href="http://code.google.com/android/c2dm/signup.html">here</a>.
</li>
</ul>
<p>In addition, you need to have some development tools:
</p>
<ul>
<li>A SQL Anywhere 12 installation such as the Developer Edition, available for free download <a href="http://www.sybase.com/detail?id=1016644">here</a>. This tutorial assumes that you have some experience with MobiLink.
</li>
<li>A Java 1.6 or later JDK.
</li>
<li>The Android SDK, downloadable from <a href="http://developer.android.com/sdk/index.html">here</a>.
</li>
<li>The Google APIs add-on for Android emulator images, downloadable from <a href="http://code.google.com/android/add-ons/google-apis/index.html">here</a>, if you wish to run the sample in an emulator.
</li>
<li>The Apache HTTP Components libraries, which can be downloaded from <a href="http://hc.apache.org/">here</a>.
</li>
</ul>
<p>And, of course, you need the sample code itself. <a href="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/08/sqlanywhere_c2dm_demo.zip">Here</a> is a zip file that has the source code for this sample application. Unzip it to create a folder named <em>distrib</em>, which you can rename or move. The two subfolders are <em>db</em> (the server-side code and database) and <em>client</em> (the client side code).
</p>
<p>Finally, you will need an Android phone. You can run the application on any Android device, or on the Android emulator that comes with the Android JDK. Some company firewalls, however, block the port that push messages use, so you may need a phone with a plan to see the push capability at work.
</p>
<p>The sample application is a simple message sending application. Random text messages (constructed from Latin words) are generated at the server, and a push system delivers them to the Android device.
</p>
<p>At each stage of this walkthrough, you may need to customize the batch files and source code to reflect your own setup.
</p>
<p><strong>Customize the Java source code<br />
</strong></p>
<p>You must edit the Java Source code to include your own C2DM account information. Open db\ml_c2db\src\com\sybase\c2dm\MessageSender.java and fill in the correct strings for C2DM_EMAIL and C2DM_PASSWORD.
</p>
<p><strong>Build the server<br />
</strong></p>
<p>The first step is to build the server-side database and logic. The build process builds the following:
</p>
<ul>
<li>The consolidated database, which is a SQL Anywhere database that holds a table for messages, a table for information about each user, and a set of tables/stored procedures that generate messages and fill the messages table. The database also has a trigger so that whenever a message is added (or deleted) a table called PushRequest is updated. The PushRequest table holds, for each user, a timestamp for the most recent message to that user.
</li>
<li>A Java package that is run by the MobiLink server.
</li>
<li>An ODBC Data source definition, which the MobiLink server uses when connecting to the consolidated database.
</li>
<li>An UltraLite database, which has the same schema as the database on the Android device. It can be used for desktop testing.
</li>
</ul>
<p>To build the server-side database and logic, open a command prompt, change directory to the <em>db</em> folder, and run <em>build.bat</em>.
</p>
<p>If you have problems running <em>build.bat</em>, you may need to edit the file to set the environment variables that point to your SQL Anywhere installation, and you may need to edit the <em>build.bat</em> file in <em>db\ml_c2dm</em>, which contains environment variables for your JDK installation as well as the location of the Apache HTTP components JAR files.
</p>
<p><strong>Customize the MobiLink server command line<br />
</strong></p>
<p>You must provide the MobiLink server with your Relay Server information. Create a file in the db folder named C2DM.config with the information from your hosted relay server account. It will look like this:
</p>
<p><span style="font-family:Consolas">-f <em>account-name.farm-name</em><br />
		</span></p>
<p><span style="font-family:Consolas">-id <em>C2DM</em><br />
		</span></p>
<p><span style="font-family:Consolas">-t <em>alongalphanumerickey</em><br />
		</span></p>
<p><span style="font-family:Consolas">-cr &#8220;host=RELAYSERVER.sybase.com;https=1;port=443;url_suffix=/ias_relay_server/server/rs_server.dll&#8221;<br />
</span></p>
<p>
 </p>
<p><strong>Start the MobiLink server<br />
</strong></p>
<p>From the db folder, run mobilink.bat to start the server.
</p>
<p>If you have problems, you may need to edit the file to set the local environment variable that points to your JDK installation directory. You may also need to change the lines that include location of the Apache HTTP components. Note that mobilink.bat contains a commented-out line that would set an appropriate setting for debugging the Java code from Eclipse. The batch file sets logging verbosity to high for debugging purposes, but if you are interested in performance you should edit the <em>mobilink.bat</em> file to reduce the logging verbosity (-v option).
</p>
<p>Part of the startup code for the MobiLink Java classes is to execute the <em>ClientLoginTokenFactory.getToken()</em> method, which sends the Sender ID and password to Google C2DM servers, and retrieves a token that MobiLink supplies as authorization when sending any subsequent messages.
</p>
<p><strong>Test the synchronization setup<br />
</strong></p>
<p>Once the MobiLink server is started properly, you can test synchronization using the <em>sync_ul.bat</em> file. This file synchronizes the MobiLink server to the C2DM.udb file created as part of the build. It doesn&#8217;t test the push part of this sample, but it does confirm that synchronization is working properly. A successful synchronization is shown as a message in the MobiLink server console window; errors will be logged in the file <em>mobilink.mls</em>, on lines starting with <strong>E.</strong> If you have problems with this synchronization, you may need to edit the file <em>build_ul.sql</em> and change the synchronization profile definition.
</p>
<p>You can inspect the data in the databases by running the isql.bat file in the db folder, which starts one instance of Interactive SQL connected to the SQL Anywhere database, and one connected to the UltraLite database. Again, you may need to edit the file to set environment variables.
</p>
<p>At this stage, there are a few messages in the consolidated database, but no additional messages are being generated.
</p>
<p>The next step is to build the Android application and test it.
</p>
<p><strong>Customize the Android application<br />
</strong></p>
<p>From Eclipse, with the Android SDK, open the project in the <em>client</em> folder. You will need to supply your own Relay Server information (so that the application can synchronize with your MobiLink server) and you will need to supply your own C2DM information (so that the application can register with the C2DM system and be matched up with your MobiLInk server.
</p>
<ul>
<li>In com.sybase.c2dm\C2DM.java, supply the ML_URL_SUFFIX needed for your Relay Server. It will be something like <em>/ias_relay_server/client/rs_client.dll/yourname-yourproject</em>.
</li>
<li>In the same file, edit the C2DM_SENDER_ID field to include our C2DM email. There is no need to supply the password on the client side.
</li>
</ul>
<p>You should now be able to build the application.
</p>
<p><strong>Build and run the Android application<br />
</strong></p>
<p>In order to run the application, you must run it on a device or emulator that has the Google APIs installed. Essentially all devices have these APIs, but you may need to download a special emulator add-on (as described at the top of this article) to use them on an emulator. You must have a Google ID (email address) to access the Google servers.
</p>
<p>Once you start the application, you should see a synchronization take place (watch the console of the MobiLink server) and some messages (random Latin words) appear on the screen. You can carry out an explicit synchronization by choosing Menu &gt; Synchronize. At this stage there will be no notifications, as no new messages are being generated. Once you have synchronization working, you can generate new messages so that push is used.
</p>
<p>The application uses <a href="http://developer.android.com/reference/android/os/AsyncTask.html">AsyncTask</a> objects to carry out database operations on a background thread, leaving the UI thread active. After creating the database, <em>DatabaseTasks.CreateOrReplaceDatabaseTask.onPostExecute()</em> calls <em>C2DM.requestC2DMRegistrationID()</em>, which posts a request to the C2DM servers for a registration ID that identifies the device to the servers. The <em>C2DMReceiver</em> class handles the response from the server, stores the registration ID in the <em>UserDevice</em> table of the application, and synchronizes it to the MobiLink server. Once this synchronization is complete, the MobiLink server can send messages to the device using the registration ID.
</p>
<p><strong>Start generating messages<br />
</strong></p>
<p>From a command prompt in the db folder, run &#8220;isql.bat sa&#8221; to open up an Interactive SQL window on the consolidated database. Enter the following command to start generating messages.
</p>
<p><span style="font-family:Consolas">alter event add_messages<br />
</span></p>
<p><span style="font-family:Consolas">enable<br />
</span></p>
<p>You can watch messages being added to the message table by executing &#8220;SELECT COUNT(*) FROM messages&#8221;. Also, you can see the PushRequest table being updated by executing &#8220;SELECT * FROM PushRequest&#8221;. To see the actions of the MobiLink server, execute &#8220;SELECT * FROM PushLog ORDER BY log_id DESC&#8221;
</p>
<p>At this point, new messages for a user prompt a push message from the MobiLink server to the Android application. On receiving the message, the application synchronizes and then notifies the user with a sound. On the emulator, the sound is not played.
</p>
<p>The sample does not include code to update the display after the message is received. You can check that messages are received by choosing Menu &gt; Refresh on the device, or by changing the orientation of the device (which prompts a refresh). To change the orientation of the emulator, press Ctrl+F11.
</p>
<p>If you are running the application on an emulator or on a device running WiFi on a company LAN, then a firewall that blocks port 5228 will prevent push messages getting to the application.
</p>
<p><strong>Summary<br />
</strong></p>
<p>So that&#8217;s the complete sample. It&#8217;s not simple, but it shows, I hope, that you can add push features to SQL Anywhere application for Android, integrating the client and the server into the Google Cloud-to-Device Messaging system.
</p>
<p>The sample code is not complete – it does not have sufficient error checking or consideration of all possible cases for a production application, but it does cover the essentials of a push application.</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2011/08/a-sql-anywhere-push-sample-for-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2011/08/a-sql-anywhere-push-sample-for-android/</feedburner:origLink></item>
		<item>
		<title>HTTPS Synchronization on Android: Handling Certificates</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/1jFJRWDpKIg/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2011/07/https-synchronization-on-android-handling-certificates/#comments</comments>
		<pubDate>Mon, 11 Jul 2011 15:29:34 +0000</pubDate>
		<dc:creator>Tom Slee, Senior Product Manager</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/2011/07/https-synchronization-on-android-handling-certificates/</guid>
		<description><![CDATA[SQL Anywhere supports HTTPS synchronization for secure transmission of data over public networks. If you are setting this up in your application, you need to have a certificate on your device that either matches a server identity (in the case of a self-signed certificate) or which is provided by a certificate authority that the MobiLink [...]]]></description>
			<content:encoded><![CDATA[<p>SQL Anywhere supports HTTPS synchronization for secure transmission of data over public networks. If you are setting this up in your application, you need to have a certificate on your device that either matches a server identity (in the case of a self-signed certificate) or which is provided by a certificate authority that the MobiLink server recognizes.</p>
<p>The HTTPS implementation on Android uses the OpenSSL library, which has slightly different behavior to the Certicom libraries that SQL Anywhere uses on other platforms. So here are some pointers on getting HTTPS synchronization to work on Android.</p>
<p><strong>Setting up the certificates</strong></p>
<p>You may already have a certificate signing mechanism set up, so you may not need this stage, but if you don&#8217;t then you can use the SQL Anywhere createcert command-line utility to create the certificates that you need. Here are two ways of creating certificates that can be used on Android.</p>
<p><em>Creating a self-signed certificate</em></p>
<p>Here is a createcert session to generate a self-signed certificate with the needed properties. The responses that I typed in are bold. Obviously the particular entries for country code and so on would be different in each case, but do notice the non-default <em>key usage</em> entry of 3,4,5,6 , which is required for this to work.</p>
<p><span style="font-family:Consolas">c:\demo&gt;<strong>createcert</strong><br />
</span> <span style="font-family:Consolas">SQL Anywhere X.509 Certificate Generator Version 12.0.1.3356</span><br />
<span style="font-family: Consolas;">Choose encryption type ((R)SA or (E)CC): <strong>r</strong></span><br />
<span style="font-family:Consolas">Enter RSA key length (512-16384): <strong>1024</strong><br />
</span> <span style="font-family:Consolas">Generating key pair&#8230;<br />
</span> <span style="font-family:Consolas">Country Code: <strong>CA</strong><br />
</span> <span style="font-family:Consolas">State/Province: <strong>ON</strong><br />
</span> <span style="font-family:Consolas">Locality: <strong>Waterloo</strong><br />
</span> <span style="font-family:Consolas">Organization: <strong>Sybase</strong><br />
</span> <span style="font-family:Consolas">Organizational Unit: <strong>iAnywhere</strong><br />
</span> <span style="font-family:Consolas">Common Name: <strong>SimpleSync</strong><br />
</span> <span style="font-family:Consolas">Enter file path of signer&#8217;s certificate:<br />
</span> <span style="font-family:Consolas">Certificate will be a self-signed root<br />
</span> <span style="font-family:Consolas">Serial number [generate GUID]:<br />
</span> <span style="font-family:Consolas">Generated serial number: a670722d106c4cc7b204e02c9c00a34c<br />
</span> <span style="font-family:Consolas">Certificate valid for how many years (1-100): <strong>1</strong><br />
</span> <span style="font-family:Consolas">Certificate Authority (Y/N) [N]: <strong>n</strong><br />
</span> <span style="font-family:Consolas">1.  Digital Signature<br />
</span> <span style="font-family:Consolas">2.  Nonrepudiation<br />
</span> <span style="font-family:Consolas">3.  Key Encipherment<br />
</span> <span style="font-family:Consolas">4.  Data Encipherment<br />
</span> <span style="font-family:Consolas">5.  Key Agreement<br />
</span> <span style="font-family:Consolas">6.  Certificate Signing<br />
</span> <span style="font-family:Consolas">7.  CRL Signing<br />
</span> <span style="font-family:Consolas">8.  Encipher Only<br />
</span> <span style="font-family:Consolas">9.  Decipher Only<br />
</span> <span style="font-family:Consolas">Key Usage [3,4,5]: <strong>3,4,5,6</strong><br />
</span> <span style="font-family:Consolas">Enter file path to save certificate: <strong>rsa_cert.pem</strong><br />
</span> <span style="font-family:Consolas">Enter file path to save private key: <strong>private_key.pem</strong><br />
</span> <span style="font-family:Consolas">Enter password to protect private key: <strong>pwd</strong><br />
</span> <span style="font-family:Consolas">Enter file path to save identity: <strong>identity.pem<br />
</strong></span></p>
<p>The generated files get used by the server (identity.pem) and by the client (rsa_cert.pem), as shown below. But first, let&#8217;s show an alternative way to generate certificates, this time using a certificate authority.</p>
<p><strong>Creating a certificate authority<br />
</strong></p>
<p>You may use a certificate from an authority such as Verisign, but here is a sample for creating your own authority, and an identity from it, using createcert.  You need to run createcert twice; once to create the certificate authority and once to generate an identity file from it. If you are using an external authority you can skip the first session.</p>
<p><em>1. Create Certificate Authority<br />
</em></p>
<p><span style="font-family:Consolas">c:\demo&gt;<strong>createcert</strong><br />
</span> <span style="font-family:Consolas">SQL Anywhere X.509 Certificate Generator Version 12.0.1.3356<br />
</span> <span style="font-family:Consolas">Choose encryption type ((R)SA or (E)CC): <strong>r</strong><br />
</span> <span style="font-family:Consolas">Enter RSA key length (512-16384): <strong>1024</strong><br />
</span> <span style="font-family:Consolas">Generating key pair&#8230;<br />
</span> <span style="font-family:Consolas">Country Code: <strong>CA</strong><br />
</span> <span style="font-family:Consolas">State/Province: <strong>Ontario</strong><br />
</span> <span style="font-family:Consolas">Locality: <strong>Waterloo</strong><br />
</span> <span style="font-family:Consolas">Organization: <strong>Sybase</strong></span><br />
<span style="font-family:Consolas"><strong></strong></span><span style="font-family: Consolas;">Organizational Unit: <strong>iAnywhere</strong></span><br />
<span style="font-family:Consolas">Common Name: <strong>MyRoot</strong><br />
</span> <span style="font-family:Consolas">Enter file path of signer&#8217;s certificate:<br />
</span> <span style="font-family:Consolas">Certificate will be a self-signed root<br />
</span> <span style="font-family:Consolas">Serial number [generate GUID]:<br />
</span> <span style="font-family:Consolas">Generated serial number: cfbbe4ac774a49f9984e470f842ba306<br />
</span> <span style="font-family:Consolas">Certificate valid for how many years (1-100): <strong>1</strong><br />
</span> <span style="font-family:Consolas">Certificate Authority (Y/N) [N]: <strong>Y</strong><br />
</span> <span style="font-family:Consolas">1.  Digital Signature<br />
</span> <span style="font-family:Consolas">2.  Nonrepudiation<br />
</span> <span style="font-family:Consolas">3.  Key Encipherment<br />
</span> <span style="font-family:Consolas">4.  Data Encipherment<br />
</span> <span style="font-family:Consolas">5.  Key Agreement<br />
</span> <span style="font-family:Consolas">6.  Certificate Signing<br />
</span> <span style="font-family:Consolas">7.  CRL Signing<br />
</span> <span style="font-family:Consolas">8.  Encipher Only<br />
</span> <span style="font-family:Consolas">9.  Decipher Only<br />
</span> <span style="font-family:Consolas">Key Usage [6,7]:<br />
</span> <span style="font-family:Consolas">Enter file path to save certificate: <strong>rsa_cert.pem</strong><br />
</span> <span style="font-family:Consolas">Enter file path to save private key: <strong>private_key.pem</strong><br />
</span> <span style="font-family:Consolas">Enter password to protect private key: <strong>pwd</strong><br />
</span> <span style="font-family:Consolas">Enter file path to save identity:<br />
</span> <span style="font-family:Consolas">Identity not saved<br />
</span></p>
<p><em>2. Create server certificate<br />
</em></p>
<p><span style="font-family:Consolas">c:\demo&gt;<strong>createcert</strong><br />
</span> <span style="font-family:Consolas">SQL Anywhere X.509 Certificate Generator Version 12.0.1.3356<br />
</span> <span style="font-family:Consolas">Choose encryption type ((R)SA or (E)CC): <strong>r</strong><br />
</span> <span style="font-family:Consolas">Enter RSA key length (512-16384): <strong>1024</strong><br />
</span> <span style="font-family:Consolas">Generating key pair&#8230;<br />
</span> <span style="font-family:Consolas">Country Code: <strong>CA</strong><br />
</span> <span style="font-family:Consolas">State/Province: <strong>Ontario</strong><br />
</span> <span style="font-family:Consolas">Locality: <strong>Waterloo</strong><br />
</span> <span style="font-family:Consolas">Organization: <strong>Sybase</strong><br />
</span> <span style="font-family:Consolas">Organizational Unit: <strong>iAnywhere</strong><br />
</span> <span style="font-family:Consolas">Common Name: <strong>SimpleSync</strong><br />
</span> <span style="font-family:Consolas">Enter file path of signer&#8217;s certificate: <strong>rsa_cert.pem</strong><br />
</span> <span style="font-family:Consolas">Enter file path of signer&#8217;s private key: <strong>private_key.pem</strong><br />
</span> <span style="font-family:Consolas">Enter password for signer&#8217;s private key: <strong>pwd</strong><br />
</span> <span style="font-family:Consolas">Serial number [generate GUID]:<br />
</span> <span style="font-family:Consolas">Generated serial number: 873b60b268754ce3ad00264bb8970a40<br />
</span> <span style="font-family:Consolas">Certificate valid for how many years (1-100): <strong>1</strong><br />
</span> <span style="font-family:Consolas">Certificate Authority (Y/N) [N]: <strong>n</strong><br />
</span> <span style="font-family:Consolas">1.  Digital Signature<br />
</span> <span style="font-family:Consolas">2.  Nonrepudiation<br />
</span> <span style="font-family:Consolas">3.  Key Encipherment<br />
</span> <span style="font-family:Consolas">4.  Data Encipherment<br />
</span> <span style="font-family:Consolas">5.  Key Agreement<br />
</span> <span style="font-family:Consolas">6.  Certificate Signing<br />
</span> <span style="font-family:Consolas">7.  CRL Signing<br />
</span> <span style="font-family:Consolas">8.  Encipher Only<br />
</span> <span style="font-family:Consolas">9.  Decipher Only<br />
</span> <span style="font-family:Consolas">Key Usage [3,4,5]:<br />
</span> <span style="font-family:Consolas">Enter file path to save certificate:<br />
</span> <span style="font-family:Consolas">Certificate not saved<br />
</span> <span style="font-family:Consolas">Enter file path to save private key:<br />
</span> <span style="font-family:Consolas">Private key not saved<br />
</span> <span style="font-family:Consolas">Enter file path to save identity: <strong>identity.pem</strong><br />
</span> <span style="font-family:Consolas">Enter password to protect private key: <strong>pwd</strong><br />
</span></p>
<p><strong>Running the MobiLink Synchronization Server<br />
</strong></p>
<p>Here is a MobiLink server command line that uses the identity file <em>identity.pem</em> (for either setup).</p>
<p><span style="font-family:Consolas">mlsrv12 -x https(port=443;tls_type=rsa;identity=identity.pem;identity_password=pwd) -c …<br />
</span></p>
<p><strong>Client side code<br />
</strong></p>
<p>Here is a synchronization profile that you can use at the client side, which needs access to the certificate (<em>rsa_cert.pem</em>). I use this for testing synchronization from Interactive SQL without needing to build an application. The statement is split across several lines for readability.</p>
<p><span style="font-family:Consolas">CREATE OR REPLACE SYNCHRONIZATION PROFILE https<br />
&#8216;MobiLinkUid=user_1;MobiLinkPwd=password_1;<br />
Stream=https{host=localhost;port=443;<br />
tls_type=rsa;trusted_certificates=rsa_root.pem};<br />
</span><span style="font-family: Consolas;">ScriptVersion=version_1&#8242;</span></p>
<p>An Android client needs to get the certificate into the right place on the client, and then use it for synchronization. Here is the process:</p>
<p>First, you need to be sure that you include the encryption library in your project. I posted about the basic setup for an UltraLite Android project <a href="http://iablog.sybase.com/mobiledatabase/2011/05/database-programming-on-android-with-ultralite/">here</a>, and all you need different is to make sure that <em>libmlcsra12.so</em> (from the UltraLite\UltraLiteJ\Android\ARM subdirectory of your SQL Anywhere install) is in the <em>libs\armeabi</em> folder of your Android project.</p>
<p>Next, in your Android project folder, create a folder <em>res\raw</em>, and add the certificate to that folder. In Eclipse this will look as follows:</p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/07/071111_1530_HTTPSSynchr1.png" alt="" /></p>
<p>Your startup code needs to read this resource and save it to the file system. Here is an example:</p>
<p><span style="font-family:Consolas"><span style="background-color:silver">InputStream</span> <span style="color:black">is = getResources().openRawResource(R.raw.</span><span style="color:#0000c0"><em>rsa_cert</em></span><span style="color:black">);</span></span><br />
<span style="font-family: Consolas;"><span style="color:black">FileOutputStream os = openFileOutput(</span><span style="color:#2a00ff">&#8220;rsa_cert.pem&#8221;</span><span style="color:black">, </span><span style="color:#0000c0"><em>MODE_PRIVATE</em></span><span style="color:black">);</span></span><br />
<span style="font-family:Consolas"><span style="color:#7f0055"><strong>byte</strong></span><span style="color:black">[] buff = </span><span style="color:#7f0055"><strong>new</strong> </span><span style="color:#7f0055"><strong>byte</strong></span><span style="color:black">[4096];</span><br />
</span> <span style="font-family:Consolas"><span style="color:#7f0055"><strong>int</strong></span><span style="color:black"> n;</span><br />
</span> <span style="font-family:Consolas"><span style="color:#7f0055"><strong>for</strong></span><span style="color:black">(;;) {</span><br />
</span> <span style="font-family:Consolas"><span style="color:black"> n = is.read(buff);</span></span><br />
<span style="font-family:Consolas"><span style="color:black"> </span><span style="color:#7f0055"> <strong>if</strong></span><span style="color:black"> (n &lt; 0) </span><span style="color:#7f0055"><strong>break</strong></span><span style="color:black">;</span><br />
</span><span style="font-family:Consolas"><span style="color:black"> os.write(buff, 0, n);</span><br />
</span><span style="color:black; font-family:Consolas">}<br />
</span></p>
<p>This adds the certificate to the files folder of your application&#8217;s private storage area, which is <em>/data/data/&lt;package-name&gt;</em>.</p>
<p>And here is the code to synchronize, reading the certificate and passing it to the synchronization function.</p>
<p><code><span style="font-family:Consolas"><span style="color:black">SyncParms sp = </span><span style="color:#0000c0">_conn</span><span style="color:black">.createSyncParms(SyncParms.</span><span style="color:#0000c0"><em>HTTPS_STREAM</em></span><span style="color:black">, </span><span style="color:#2a00ff">"user_1"</span><span style="color:black">, </span><span style="color:#2a00ff">"version_1"</span><span style="color:black">);</span><br />
</span><span style="font-family:Consolas"><span style="color:black">sp.setPassword(</span><span style="color:#2a00ff">"password_1"</span><span style="color:black">);</span></span><br />
<span style="font-family:Consolas"><span style="color:black">StreamHTTPSParms streamParms = (StreamHTTPSParms)sp.getStreamParms();</span></span><br />
<span style="font-family:Consolas"><span style="color:black">streamParms.setHost(</span><span style="color:#2a00ff">"10.0.2.2"</span><span style="color:black">); </span><span style="color:#3f7f5f">// This is the URL that identifies the host machine for the emulator</span></span><br />
<span style="font-family:Consolas"><span style="color:black">streamParms.setPort(443);</span></span><br />
<span style="font-family:Consolas"><span style="color:black">streamParms.setTrustedCertificates(</span><span style="color:#2a00ff">"/data/data/com.sybase.simplesync/files/rsa_cert.pem"</span><span style="color:black">);</span></span><br />
<span style="font-family:Consolas"><span style="color:#0000c0">_conn</span><span style="color:black">.synchronize(sp);<br />
</span></span></code></p>
<p>So that describes how to create certificates for HTTPS synchronization on Android, how to use them at the server, and how to use them at the client.</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2011/07/https-synchronization-on-android-handling-certificates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2011/07/https-synchronization-on-android-handling-certificates/</feedburner:origLink></item>
		<item>
		<title>How Long Does a Sync Take?</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/RYrjx7lnuR0/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2011/05/how-long-does-a-sync-take/#comments</comments>
		<pubDate>Mon, 30 May 2011 17:54:07 +0000</pubDate>
		<dc:creator>Tom Slee, Senior Product Manager</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[blackberry]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/2011/05/how-long-does-a-sync-take/</guid>
		<description><![CDATA[It&#8217;s a question we get asked all the time, and of course it is tempting to answer &#8220;it depends&#8221;. Because it does depend – it depends on the network, the device being synchronized, the data volume, the data distribution, the number of indexes, the consolidated database at the other end of the synchronization and probably [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s a question we get asked all the time, and of course it is tempting to answer &#8220;it depends&#8221;. Because it does depend – it depends on the network, the device being synchronized, the data volume, the data distribution, the number of indexes, the consolidated database at the other end of the synchronization and probably other things I haven&#8217;t thought of. How long is a piece of string?</p>
<p>But still, people understandably want to know, how long <em>does</em> a sync take? And sometimes I have the feeling that people think of data synchronization as a heavy, time consuming process – perhaps thinking back to pushing the button on old PDAs – when much of the time it is anything but.</p>
<p>So here are some syncs and the times they take. These are all download syncs (getting data from the consolidated database to the device), because for many applications the biggest sync happens the first time the application is started, when it downloads the data it needs. After that, it&#8217;s often incremental changes that are much easier to manage. They are all done with a light server load (we document MobiLink server throughput and scalability <a href="http://www.sybase.com/detail?id=1009664">here</a>) because the focus is on the experience at the client. The MobiLink server is running on my desktop, but communication goes through a Relay Server on the other side of the continent so this data is recorded over realistic networks.</p>
<p>Here is data from an HTC Desire running Android 2.2, over a WiFi network.</p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/05/053011_1754_HowLongDoes1.png" alt="" /></p>
<p>You can see that downloads of anything less than 100KB or so can be done in under two seconds, from request to the successful completion. Put this in the background, and it means that data transfer can take place with basically no interruption to the user.  Once or twice network connectivity issues led to delays (the two off-line points) but for most cases you can see that the download time is linear with data volume. You can see that this extends to higher volumes in the next figure.</p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/05/053011_1754_HowLongDoes2.png" alt="" /></p>
<p>The top-right value here is a download of 50MB of data, and it takes about 15 minutes. In practice, most downloads of this size to a smartphone, tablet or handheld computer will be on initial setup of an application (the initial loading of reference data) and this can be better achieved by downloading a pre-populated database file. But if you do need to synchronize this much data, it can be done.</p>
<p>And here is data from a BlackBerry Bold 9700 downloading data over a 2G or 3G network (the higher values for a given volume are 2G). You can see from the log-log plot that the smallest download (a few KB) has an overhead of a few seconds, which is a reflection of the latency of the network. A download of a megabyte of data can be accomplished in about a minute (a rate of about 15KB/s). The largest sync, which is 10MB, takes about 15 minutes to complete. For downloads of this magnitude, you may want to consider using the MobiLink file transfer capability instead to download a database file, rather than to download the data and insert it into the file.</p>
<p>There are downloads for four different schemas, at various scale factors, included in the single graph below.</p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/05/053011_1754_HowLongDoes3.png" alt="" /></p>
<p>You can see that the times for BlackBerry are significantly longer than those for the Android device. This is partly because of the slower network, partly because of the less-powerful device, and partly because of the overhead from Java software on the BlackBerry.</p>
<p>The takeaway message here, I&#8217;d like to think, is that data synchronization is not a heavy operation, but is often a short operation that, when carried out on a background thread, can be done with no interruption to the user experience.</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2011/05/how-long-does-a-sync-take/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2011/05/how-long-does-a-sync-take/</feedburner:origLink></item>
		<item>
		<title>Database Programming on Android with UltraLite</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/e8WEO90fYL8/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2011/05/database-programming-on-android-with-ultralite/#comments</comments>
		<pubDate>Sun, 01 May 2011 23:58:59 +0000</pubDate>
		<dc:creator>Tom Slee, Senior Product Manager</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/2011/05/database-programming-on-android-with-ultralite/</guid>
		<description><![CDATA[Now that SQL Anywhere has support for Android, this blogger will finally get his act together enough to post some new material. This is the first of a few posts for those new to Android spelling out some techniques for writing database applications on that platform. UltraLite is the mobile database management system that is [...]]]></description>
			<content:encoded><![CDATA[<p>Now that <a href="http://www.sybase.com/products/databasemanagement/sqlanywhere"><span style="color:#663333; font-family:Tahoma; font-size:10pt">SQL Anywhere</span></a><span style="color:#333333; font-family:Tahoma; font-size:10pt"> has support for Android, this blogger will finally get his act together enough to post some new material. This is the first of a few posts for those new to Android spelling out some techniques for writing database applications on that platform.<br />
</span></p>
<p><span style="font-family:Tahoma; font-size:10pt"><span style="color:#333333">UltraLite is the mobile database management system that is included in SQL Anywhere. This post is a Hello World for UltraLite on Android. It assumes that you have what you need to develop Android applications (Eclipse and the Android SDK), and that you have SQL Anywhere installed (perhaps the <a href="http://www.sybase.com/detail?id=1016644"></a></span>Developer Edition free download<span style="color:#333333">). It covers setting up a project, and carrying out simple database access, but doesn&#8217;t cover data synchronization (sharing data between device and a backend system) which is the primary reason for many people to choose SQL Anywhere.<br />
</span></span></p>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">First, create an Android Project. Here are the settings I&#8217;ll be using.<br />
</span></p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/05/050111_2358_DatabasePro1.png" alt="" /><span style="color:#333333; font-family:Tahoma; font-size:10pt"><br />
</span></p>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">Once you have created the project you should be able to run this default application in an emulator (or on a device) and see that it shows a screen with the words &#8220;Hello World, Hello UltraLite&#8221; in a textView control. Choose Run &gt; Run As &gt; Android Application.<br />
</span></p>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">Next, create a folder named libs\ under the HelloUltraLite folder, and copy the UltraLiteJ files into it. You will need to rename the ARM subfolder to armeabi. Here are the instructions from a command line:<br />
</span></p>
<p><span style="color:#333333; font-family:Consolas; font-size:10pt">workspace&gt; mkdir HelloUltraLite\libs<br />
</span></p>
<p><span style="color:#333333; font-family:Consolas; font-size:10pt">workspace&gt; xcopy /s &#8220;c:\Program Files\SQL Anywhere 12\UltraLite\UltraLiteJ\Android\*.*&#8221; HelloUltraLite\libs<br />
</span></p>
<p><span style="color:#333333; font-family:Consolas; font-size:10pt">workspace&gt; move HelloUltraLite\libs\ARM HelloUltraLite\libs\armeabi<br />
</span></p>
<p><span style="color:#333333; font-size:10pt">The UltraLite files include the UltraLite JAR file (which holds the API), the UltraLite database management system, which is a C++ shared object, and the Javadoc documentation files.<br />
</span></p>
<p><span style="color:#333333; font-size:10pt">Back in Eclipse, add the UltraLite libraries to your project:<br />
</span></p>
<p><span style="color:#333333; font-size:10pt">In the package explorer press F5 or right click the project and choose Refresh so that the project is aware of the UltraLite files.<br />
</span></p>
<p><span style="color:#333333; font-size:10pt">Add the UltraLite JAR file to your build path, as in the following dialog. You can also specify the Javadoc location as the libs\HTML subfolder of your project so that you get tooltip-style documentation from the edit window:<br />
</span></p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/05/050111_2358_DatabasePro2.png" alt="" /><span style="color:#333333; font-family:Tahoma; font-size:10pt"><br />
</span></p>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">Here is what the Package Explorer looks like, with the libs folder included.<br />
</span></p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/05/050111_2358_DatabasePro3.png" alt="" /><span style="color:#333333; font-family:Tahoma; font-size:10pt"><br />
</span></p>
<p><span style="color:#333333; font-size:10pt"><span style="font-family:Tahoma">The next step is to add some code to the </span><span style="font-family:Consolas">com.sybase.com.HelloUltraLite.java</span><span style="font-family:Tahoma"> file to create and connect to a database. Most of the time you would keep your data access code in a separate class, but for this simple case we are going to keep everything in one file.<br />
</span></span></p>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">Here are the imports that the file needs:<br />
</span></p>
<pre><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>import</strong></span><span style="color:black"> java.util.Random;
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>import</strong></span><span style="color:black"> android.app.Activity;
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>import</strong></span><span style="color:black"> android.os.Bundle;
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>import</strong></span><span style="color:black"> android.util.Log;
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>import</strong></span><span style="color:black"> android.widget.TextView;
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>import</strong></span><span style="color:black"> com.ianywhere.ultralitejni12.*;</span></span></pre>
<p><span style="color: #333333;"><span style="font-family:Tahoma">When Android starts the application in response to a tap of the icon, the entry point is the </span><span style="font-family:Consolas">HelloUltraLite onCreate()</span><span style="font-family:Tahoma"> method, so that is where we will put the database access code. Here is the complete onCreate() method:</span></span></p>
<pre><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>public</strong></span> <span style="color:#7f0055"><strong>void</strong></span><span style="color:black"> onCreate(Bundle savedInstanceState) {
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>    super</strong></span><span style="color:black">.onCreate(savedInstanceState);
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">    setContentView(R.layout.</span><span style="color:#0000c0"><em>main</em></span><span style="color:black">);
</span></span><span style="font-family: Consolas;"><span style="color:#7f0055"><strong>     try</strong></span><span style="color:black">{
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#3f7f5f">        // Define the database properties using a Configuration object
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ConfigFileAndroid config = DatabaseManager.<span style="background-color:silver"><em>createConfigurationFileAndroid</em></span>(</span><span style="color:#2a00ff">"hello.udb"</span><span style="color:black">, </span><span style="color:#7f0055"><strong>this</strong></span><span style="color:black">);</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#3f7f5f">        // Connect, or if the database does not exist, create it and connect</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>        try</strong></span><span style="color:black">{
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">            </span><span style="color:#0000c0">_conn</span><span style="color:black"> = DatabaseManager.<span style="background-color:silver"><em>connect</em></span>(config);
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        } </span><span style="color:#7f0055"><strong>catch</strong></span><span style="color:black"> ( ULjException e) {
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">            </span><span style="color:#0000c0">_conn</span><span style="color:black"> = DatabaseManager.<span style="background-color:silver"><em>createDatabase</em></span>(config);   �
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        }</span></span>
 <span style="font-family:Consolas; font-size:12pt"><span style="color:black">
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#3f7f5f">        // Create a table T1 in the database if it does not exist
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        StringBuffer sb = </span><span style="color:#7f0055"><strong>new</strong></span><span style="color:black"> StringBuffer();
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        sb.append(</span><span style="color:#2a00ff">"CREATE TABLE IF NOT EXISTS T1 (C1 integer primary key default autoincrement, C2 integer )"</span><span style="color:black">);
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        PreparedStatement ps = </span><span style="color:#0000c0">_conn</span><span style="color:black">.<span style="background-color:silver">prepareStatement</span>(sb.toString());
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ps.<span style="background-color:silver">execute</span>();
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ps.<span style="background-color:silver">close</span>();
</span></span>           <span style="font-family:Consolas; font-size:12pt"><span style="color:black">
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#3f7f5f">        // Insert a row into T1
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        sb = </span><span style="color:#7f0055"><strong>new</strong></span><span style="color:black"> StringBuffer(</span><span style="color:#2a00ff">"INSERT INTO T1 (C2) ON EXISTING SKIP VALUES ( ? )"</span><span style="color:black">);
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ps = </span><span style="color:#0000c0">_conn</span><span style="color:black">.<span style="background-color:silver">prepareStatement</span>(sb.toString());
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ps.<span style="background-color:silver">set</span>(1, </span><span style="color:#7f0055"><strong>new</strong></span><span style="color:black"> Random().nextInt());
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ps.<span style="background-color:silver">execute</span>();
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ps.<span style="background-color:silver">close</span>();</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#0000c0">        _conn</span><span style="color:black">.<span style="background-color:silver">commit</span>();
</span></span></pre>
<pre><span style="font-family:Consolas; font-size:12pt"><span style="color:#3f7f5f">        // Select the values from C2 and show them in the user interface
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        sb = </span><span style="color:#7f0055"><strong>new</strong></span><span style="color:black"> StringBuffer(</span><span style="color:#2a00ff">"SELECT C2 FROM T1"</span><span style="color:black">);
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ps = </span><span style="color:#0000c0">_conn</span><span style="color:black">.<span style="background-color:silver">prepareStatement</span>(sb.toString());
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        ResultSet rs = ps.<span style="background-color:silver">executeQuery</span>();
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        StringBuffer c2 = </span><span style="color:#7f0055"><strong>new</strong></span><span style="color:black"> StringBuffer();</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:#7f0055"><strong>        while</strong></span><span style="color:black">(rs.<span style="background-color:silver">next</span>()){
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">            c2.append(String.<em>valueOf</em>(rs.<span style="background-color:silver">getInt</span>(1)));
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">            c2.append(</span><span style="color:#2a00ff">","</span><span style="color:black">);
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        }
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        TextView tv = (TextView)findViewById(R.id.</span><span style="color:#0000c0"><em>textview1</em></span><span style="color:black">);
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        tv.setText(c2.toString());
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">    } </span><span style="color:#7f0055"><strong>catch</strong></span><span style="color:black"> ( <span style="background-color:silver">ULjException</span> e) {
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">        Log.<em>e</em>(</span><span style="color:#2a00ff">"HelloUltraLite"</span><span style="color:black">, e.toString());
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">    }
</span></span><span style="font-family:Consolas; font-size:12pt"><span style="color:black">}</span></span></pre>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">The class R is the Resource class, and includes the user interface and any strings.<br />
</span></p>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">When this application is run, it carries out the following tasks:<br />
</span></p>
<ol>
<li><span style="color:#333333; font-family:Tahoma; font-size:10pt">Connects to a database, or creates the database if it does not exist (and returns a connection)<br />
</span></li>
<li><span style="color:#333333; font-family:Tahoma; font-size:10pt">Creates a table T1 if it does not already exist<br />
</span></li>
<li><span style="color:#333333; font-family:Tahoma; font-size:10pt">Inserts a row into T1.<br />
</span></li>
<li><span style="color:#333333; font-family:Tahoma; font-size:10pt">Selects all the rows from T1, concatenates them into a string, and displays that string in the TextView control that is included in the default user interface.<br />
</span></li>
<li><span style="color:#333333; font-family:Tahoma; font-size:10pt">If there is an error, a message is written out to the LogCat window in the Eclipse user interface.<br />
</span></li>
</ol>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">Here is the Android application after running the application a few times, showing the random numbers inserted into the table.<br />
</span></p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/05/050111_2358_DatabasePro4.png" alt="" /><span style="color:#333333; font-family:Tahoma; font-size:10pt"><br />
</span></p>
<p><span style="color:#333333; font-family:Tahoma; font-size:10pt">And that completes the tutorial.<br />
</span></p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2011/05/database-programming-on-android-with-ultralite/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2011/05/database-programming-on-android-with-ultralite/</feedburner:origLink></item>
		<item>
		<title>SQL Anywhere Now Available For Android</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/qjmjEbAO4Bo/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2011/03/sql-anywhere-now-available-for-android/#comments</comments>
		<pubDate>Thu, 10 Mar 2011 20:51:33 +0000</pubDate>
		<dc:creator>Tom Slee, Senior Product Manager</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[UltraLite Development]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/2011/03/sql-anywhere-now-available-for-android/</guid>
		<description><![CDATA[One of the new features in SQL Anywhere 12.0.1 is support for Android. This means that the UltraLite database, previously available on Windows Mobile, Windows, BlackBerry and iPhone, is now also available on Android. Mobile enterprise applications on Android can now take advantage of the same on-device database and data synchronization technology as apps on [...]]]></description>
			<content:encoded><![CDATA[<p>One of the new features in <a href="http://www.sybase.com/products/databasemanagement/sqlanywhere">SQL Anywhere 12.0.1</a> is support for Android. This means that the UltraLite database, previously available on Windows Mobile, Windows, BlackBerry and iPhone, is now also available on Android. Mobile enterprise applications on Android can now take advantage of the same on-device database and data synchronization technology as apps on other leading mobile device operating systems.</p>
<p>Here is the architecture of a typical SQL Anywhere mobile application:</p>
<p><img src="http://iablog.sybase.com/mobiledatabase/wp-content/uploads/2011/03/031011_2051_SQLAnywhere11.png" alt="" /></p>
<p>The logic that decides who gets what data is held at the synchronization server; the traffic optionally goes through a relay server which eliminates the need for inbound traffic through the firewall, and the local database on the device makes it possible to build responsive, always-available applications that use rich data sets.</p>
<p>SQL Anywhere has a significant number of mobile deployments with tens of thousands of mobile devices, so the technology is proven to scale to large numbers of clients. The free Developer Edition is available for download <a href="http://www.sybase.com/detail?id=1016644">here</a> (you need the Windows Edition as development is carried out on Windows), and there is <a href="http://dcx.sybase.com/index.html">documentation</a> at the DCX web site that <a href="http://iablog.sybase.com/mobiledatabase/2011/03/everyone-should-have-dcx/">Phillipe just wrote about</a>. <a href="http://dcx.sybase.com/index.html#1201en/ulj/uj-android-tutorial.html">Here</a> is an introductory tutorial.</p>
<p>Our Android implementation uses the same <a href="http://dcx.sybase.com/index.html#1201en/ulj/uj-apiref-chapter-5026866.html">UltraLiteJ Java API</a> as that of our BlackBerry database. Under the covers, though, we have used the Android NDK to provide a C/C++ library for better performance – a port of the same code base that is supplied on Windows Mobile and iPhone. This means that although the Android implementation is new, the database code itself is mature and extensively field-tested.</p>
<p>I hope to write a small set of posts in the near future that focus on the Android-specific client, its performance and what you need to develop applications. Those posts will be based on the content of a webcast we gave last week, which you can find on the Resources tab <a href="http://www.sybase.com/products/databasemanagement/sqlanywhere">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2011/03/sql-anywhere-now-available-for-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2011/03/sql-anywhere-now-available-for-android/</feedburner:origLink></item>
		<item>
		<title>Everyone should have DCX</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/icUA04E3qUE/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2011/03/everyone-should-have-dcx/#comments</comments>
		<pubDate>Thu, 10 Mar 2011 03:15:09 +0000</pubDate>
		<dc:creator>Philippe Bertrand, Software Developer</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[thingsiwant]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/?p=225</guid>
		<description><![CDATA[I&#8217;m a developer. I often spend my days searching API documentation while doing research. A day ago, in this role, I started to get quite frustrated at the lack of details that a vendor provided &#8211; &#8220;why couldn&#8217;t they have something like our DCX?&#8221; I thought. To say that some of the classes had sparse [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a developer.  I often spend my days searching API documentation while doing research.  A day ago, in this role, I started to get quite frustrated at the lack of details that a vendor provided &#8211; &#8220;why couldn&#8217;t they have something like our DCX?&#8221; I thought.  To say that some of the classes had sparse documentation is an understatement.</p>
<p>When I&#8217;m looking up our docs (way too much to memorize and faster than looking it up in the code) and see something weak or confusing, I simply add a comment.  If it is in my own product, I add a clarification visible to all.  It&#8217;s the same as emailing our doc team and it makes the clarification available to our customers.</p>
<p>So where am I going with this?  Following the theme of <a href="http://iablog.sybase.com/mobiledatabase/2011/01/all-i-wanted-for-christmas-was-feedback/">my previous post</a>, all vendors should have a site like <a href="http://dcx.sybase.com">our DCX</a>!</p>
<p><strong>And</strong> all users of SQL Anywhere should take advantage of DCX.  Don&#8217;t get me wrong, our doc team and developers who provide documentation are quite busy so a massive flood would have to be prioritized.  Yet even a volume of constructive requests for clarification will help us know what sections of API are used frequently and really could benefit from improvement.  While the docs themselves are not updated until the next release, we do post responses to comments when we feel they would be of benefit to the general user base.</p>
<p>Of course, sometimes what is needed is much more that what would be appropriate in an API reference.  This is where the newsgroups and the SQL Anywhere forum (which is currently in beta) comes in.  Here not only can Sybase iAnywhere staff provide answers and samples, the whole user community can share and grow to the benefit of all!</p>
<p>As I said, I&#8217;m a developer, and in my utopian world, all developers would have perfect documentation.  In the meantime, everyone should have and use DCX-like documentation.</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2011/03/everyone-should-have-dcx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2011/03/everyone-should-have-dcx/</feedburner:origLink></item>
		<item>
		<title>All I wanted for Christmas was Feedback!</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/O84j0aZZTVI/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2011/01/all-i-wanted-for-christmas-was-feedback/#comments</comments>
		<pubDate>Tue, 04 Jan 2011 19:52:17 +0000</pubDate>
		<dc:creator>Philippe Bertrand, Software Developer</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[thingsiwant]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/?p=223</guid>
		<description><![CDATA[And not the electric guitar kind&#8230; Yes, I&#8217;m a developer working deep down in the bowels of the code &#8211; striving to make it better, faster, able to leap tall buildings in a single bound. The problem is UltraLite and UltraLiteJ are just one piece of a great mobility solution offered by us and is [...]]]></description>
			<content:encoded><![CDATA[<p>And not the electric guitar kind&#8230;</p>
<p>Yes, I&#8217;m a developer working deep down in the bowels of the code &#8211; striving to make it better, faster, able to leap tall buildings in a single bound.  The problem is UltraLite and UltraLiteJ are just one piece of a great mobility solution offered by us and is in fact, not even sold as a separate product.  We don&#8217;t get nearly as good a feel as to who is using it and what is being done with it.  Sure we (Product Management and Development) hear about some of the big projects but we know there are some very interesting uses out there that slip our radar.</p>
<p>So why should you care?  I can sum it all up with one example.  A number of months ago we had a pre-sales inquiry as to whether UltraLiteJ could handle a particular scenario.  Product management or our support specialist quickly created a sample and tried it out on a device to promptly discover that, yes indeed, UltraLiteJ could easily meet the performance requirements given the particulars of the request.</p>
<p>Yet the story does not end here.  They told me about this customer and described to me the environment they were working in (we were lucky because we were given the full schema and class of devices).  This sat in the back of my mind for a little bit when another issue came up that brought this story to the foreground.  I figured out that there could be some issues that would not show up unless the client application ran for a significant amount of time.  We added better code and thus UltraLiteJ was improved, to the benefit of all, long before the customer went to production.</p>
<p>What caught our attention were the particulars of the environment (ok, it is hard to write this while keeping the details private because I don&#8217;t know if we are under NDA) &#8211; it wasn&#8217;t a giant deal but it was a neat everyday use of our technology &#8211; one we might encounter in our everyday travels and it didn&#8217;t come from the usual support channels.</p>
<p>Letting us (Product Management at Sybase iAnywhere) know the environments our technology works in lets us plan and think about what features we can add to make your life better.  While we can&#8217;t customize the product for every customer, we can look at common issues and ease of use features that will help everyone.</p>
<p>Make providing feedback a New Years Resolution and Happy New Year!</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2011/01/all-i-wanted-for-christmas-was-feedback/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2011/01/all-i-wanted-for-christmas-was-feedback/</feedburner:origLink></item>
		<item>
		<title>Hurray for UltraLiteJ 12</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/X0japWPIkww/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2010/11/hurray-for-ultralitej-12/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 15:07:47 +0000</pubDate>
		<dc:creator>Philippe Bertrand, Software Developer</dc:creator>
				<category><![CDATA[blackberry]]></category>
		<category><![CDATA[UltraLite Development]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/?p=221</guid>
		<description><![CDATA[While UltraLiteJ 11 release was a milestone in our support of the BlackBerry platform, much changed in the mobile environment and UltraLiteJ 12 has significant new features and under the cover improvements to take advantage of the newest BlackBerry devices. Before I delve into this, a little background … We had been experimenting for years [...]]]></description>
			<content:encoded><![CDATA[<p>While UltraLiteJ 11 release was a milestone in our support of the BlackBerry platform,  much changed in the mobile environment and UltraLiteJ 12 has significant new features and under the cover improvements to take advantage of the newest BlackBerry devices.  Before I delve into this, a little background …</p>
<p>We had been experimenting for years on BlackBerry devices before the first release of UltraLiteJ, but the very features that endeared the BlackBerry to the corporate users – long battery life – was holding back the development of advanced database synchronization technology for this platform.  Despite our years of experience in the mobile space, the clocked down processors, slow persistent memory and object handle limits of the BlackBerry made it impossible for us to achieve the minimum performance we deem acceptable – that was until the 4.0 devices arrived.  Even with the 8700, we did many experiments before arriving with the architecture of UltraLiteJ.  We would not compromise in ensuring we had a reliable product that would provide a recoverable database.</p>
<p>But that was then … before cameras and SD cards.  So now SQL Anywhere 12 was release this summer, with UltraLiteJ 12.</p>
<p>There are lots of great new features, including MobiLink file transfers, BlackBerry internal flash and SD card support, and support for binary data in external files (i.e. pictures taken by the on device camera become part of the database without time consuming copying).  While all these features and more give UltraLiteJ some good kick, what I really want to talk about is what is hidden under the covers!</p>
<p>For 12, we made some fundamental changes to the underlining architecture to address scalability and performance.  First of all we implemented a new row limiting algorithm to make it easier for users to manage the BlackBerry’s unique object handle issues (yes, row limiting in not new in 12 but the old algorithm did not handle the fact that different tables use up different number of handles per row).  Next we added better management of index pages, better storage (both in memory and persistent form) of the transaction log, improvements for large downloads and finally, we greatly reduced database page read and writes.  Basically, stuff guys like me love to brag about.</p>
<p>We tried to push as many partial and full performance improvements into the 11 “express bug fix” releases as we could but the full benefit could not be achieved without the store format change that occurred in 12.</p>
<p>So if you are still on 11, what are you waiting for?  Upgrade to UltraLiteJ 12 and reap the benefits!</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2010/11/hurray-for-ultralitej-12/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2010/11/hurray-for-ultralitej-12/</feedburner:origLink></item>
		<item>
		<title>Computerworld: “Mobile increasingly driving the IT bus”</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/Ebdn55NdAko/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2010/10/computerworld-mobile-increasingly-driving-the-it-bus/#comments</comments>
		<pubDate>Wed, 20 Oct 2010 14:00:29 +0000</pubDate>
		<dc:creator>Tom Slee, Senior Product Manager</dc:creator>
				<category><![CDATA[in the news]]></category>
		<category><![CDATA[industry]]></category>
		<category><![CDATA[mobility market]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/?p=217</guid>
		<description><![CDATA[It&#8217;s nice to see Computerworld&#8217;s Robert L. Mitchell report that &#8220;One interesting undercurrent here at the Gartner IT Symposium this week is the extent to which mobile computing is forcing everyone to adapt. The need to accommodate the consumer&#8217;s choice of end point mobile computing devices, each with its own application infrastructure and network, is [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s nice to see Computerworld&#8217;s Robert L. Mitchell <a title="Computerworld article" href="http://blogs.computerworld.com/17199/gartner_symposium_mobile_increasingly_driving_the_it_bus" target="_blank">report</a> that &#8220;One interesting undercurrent here at the Gartner IT Symposium this week is the extent to which mobile computing is forcing everyone to adapt. The need to accommodate the consumer&#8217;s choice of end point mobile computing devices, each with its own application infrastructure and network, is increasingly being taken as a given.&#8221;</p>
<p>One interesting point is that multiple devices are becoming the norm. This is one of those trends that seems to go in multiple directions at once. In some ways the smartphone is driving out other devices (watches, alarm clocks, music players) and the world looks like it is converging on one device, but at the same time we adopt e-readers, tablets, and more. As Mitchell says:</p>
<blockquote><p>The conventional wisdom was that people would never carry an iPad or other tablet computer because it can&#8217;t replace a smart phone or a laptop and no one would carry three devices. It&#8217;s looking like that&#8217;s not true. iPad users here appear to be carrying all three &#8211; including another Computerworld reporter covering the conference. Gartner now envisions a world where users&#8217; lives are associated with many different devices, a world where those devices will disappear into functional &#8220;objects&#8221; (think e-book reader).</p></blockquote>
<p>And all these pockets and bags full of devices drive another need, which Mitchell calls &#8220;The synch ecosystem&#8221;:</p>
<blockquote>
<p style="margin-top: 8px; margin-right: 0px; margin-bottom: 8px; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 15px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: #333333; line-height: 20px; background-position: initial initial; background-repeat: initial initial; padding: 0px; border: 0px initial initial;">An acute need is emerging for app and data orchestration between all of these computing devices. What all of those objects you use need is portable, universal access to your information. &#8220;If you&#8217;re working on four or five different machines you can&#8217;t remember which has what,&#8221; says Cearley. And you shouldn&#8217;t have to.</p>
</blockquote>
<p style="margin-top: 8px; margin-right: 0px; margin-bottom: 8px; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 15px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: #333333; line-height: 20px; background-position: initial initial; background-repeat: initial initial; padding: 0px; border: 0px initial initial;">Most often when I think about moving data from device to device I am thinking about sharing it among different users, but the point here is that there is a real need to share my data with myself at different points in my day, and this sharing should be transparent. It&#8217;s something that we are working on here at Sybase, and good to hear that it&#8217;s a task others think is important.</p>
<p style="margin-top: 8px; margin-right: 0px; margin-bottom: 8px; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 15px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: #333333; line-height: 20px; background-position: initial initial; background-repeat: initial initial; padding: 0px; border: 0px initial initial;">I recommend reading the <a href="http://blogs.computerworld.com/17199/gartner_symposium_mobile_increasingly_driving_the_it_bus">whole article</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2010/10/computerworld-mobile-increasingly-driving-the-it-bus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2010/10/computerworld-mobile-increasingly-driving-the-it-bus/</feedburner:origLink></item>
		<item>
		<title>Choosing a Sybase Technology for your Mobile Applications</title>
		<link>http://feedproxy.google.com/~r/WanderingData/~3/t4IFgwJ7Vts/</link>
		<comments>http://iablog.sybase.com/mobiledatabase/2010/09/choosing-a-sybase-technology-for-your-mobile-applications/#comments</comments>
		<pubDate>Tue, 21 Sep 2010 14:13:34 +0000</pubDate>
		<dc:creator>Tom Slee, Senior Product Manager</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[mobility platforms]]></category>
		<category><![CDATA[sqlanywhere]]></category>
		<category><![CDATA[sup]]></category>

		<guid isPermaLink="false">http://iablog.sybase.com/mobiledatabase/?p=211</guid>
		<description><![CDATA[The Sybase Mobility Platform is a comprehensive set of new and industry-proven solutions to help companies go mobile. It includes both Sybase Unwired Platform (SUP) and SQL Anywhere: two technologies for building powerful mobile applications, but which one is right for you? Here are a couple of things I find it helpful to keep in [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.sybase.com/detail?id=1080021">Sybase Mobility Platform</a> is a comprehensive set of new and industry-proven solutions to help companies go mobile. It includes both Sybase Unwired Platform (SUP) and SQL Anywhere: two technologies for building powerful mobile applications, but which one is right for you? Here are a couple of things I find it helpful to keep in mind when making the decision.</p>
<p>First: which devices are you targeting with your application?</p>
<p>SUP is designed for the burgeoning world of smartphone applications, with support for BlackBerry, iPhone, Windows Mobile and Symbian smartphones and handheld devices.</p>
<p>While SQL Anywhere also supports smartphone platforms, most SQL Anywhere mobile applications are deployed on enterprise handheld computers and on laptop computers. Delivery, logistics and warehouse applications are common users of handheld computers; inspections, CRM and field service applications are often deployed to laptops.</p>
<p>In addition, SQL Anywhere supports &#8220;remote office&#8221; and point-of-sale systems which, while not &#8220;mobile&#8221; in a strict sense, share a common data architecture with mobile applications. The &#8220;mobile device&#8221; in this case may be a multi-user database server at a regional office, restaurant or other location – typically with limited or no IT staff.</p>
<p>Second: SUP and SQL Anywhere provide a different experience for developers, both on device and at the enterprise.</p>
<p>SUP developers can take advantage of a 4GL programming model which uses Mobile Business Objects to generate application code from an Eclipse-based workspace. Mobile Business Objects provide a level of abstraction that unifies the device, data movement, and enterprise integration aspects of mobile applications and which insulates the developer from the need for low-level programming. Developers using SQL Anywhere work directly with low-level APIs and use the SQL language for data manipulation: this approach takes more work but provides maximum control and performance.</p>
<p>On device, SUP Mobile Business Objects allow device-independent generation of application code, while SQL Anywhere developers work directly in the native application programming tools and native APIs for each device.</p>
<p>At the enterprise, SQL Anywhere is focused on working directly with relational database management systems, including Oracle, Sybase, Microsoft and IBM DB2. SUP is designed to work more closely with enterprise systems such as SAP.</p>
<p>In short, SQL Anywhere provides optimized components for each device and for data movement, allowing maximum control for high-performance and highly scalable applications. SUP&#8217;s higher level of abstraction lets developers produce applications more rapidly, and the SUP server is built for organizations building multiple mobile applications.</p>
]]></content:encoded>
			<wfw:commentRss>http://iablog.sybase.com/mobiledatabase/2010/09/choosing-a-sybase-technology-for-your-mobile-applications/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://iablog.sybase.com/mobiledatabase/2010/09/choosing-a-sybase-technology-for-your-mobile-applications/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 0.543 seconds. --><!-- Cached page generated by WP-Super-Cache on 2012-02-08 17:00:19 -->

