tag:blogger.com,1999:blog-56731370626744980912024-03-13T13:20:40.928-04:00Arbitrary Computer Code MusingsA totally arbitrary set of notes themed around various topics of software development widely ranging from code examples and how-to's to development processes and maybe even some computing-inspired philosophical musings.
<br>
"It's an island, babe. If you don't bring it here, you won't find it here."<br>
"Whoa, heavy. Pilot and philosopher!"<br>
(From the <a href="http://www.imdb.com/title/tt0120828/quotes">Six Days Seven Nights</a> movie)Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-5673137062674498091.post-29918251126760622402016-12-12T21:14:00.000-05:002016-12-12T21:14:05.108-05:00JUnit based on Spring MVC Test framework fails with AuthenticationCredentialsNotFoundException<br />
After adding the second servlet and a servlet mapping to the web.xml configuration of a Spring-based web application, a JUnit test that relied on the <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#spring-mvc-test-framework" target="_blank">Spring MVC Test framework</a> started to fail.<br />
The unit test was used to verify proper functioning of controller security layer that is based on Spring Security framework (v3.2.9 at the time).<br />
<br />
The JUnit code (fragments):<br />
<br />
@ContextConfiguration(loader = WebContextLoader.class, locations = {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>"classpath:spring/application-context.xml",<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>"classpath:spring/servlet-context.xml",<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>"classpath:spring/application-security.xml"})<br />
public class AuthenticationIntegrationTest extends AbstractTransactionalJUnit4SpringContextTests {<br />
<div>
<div>
@Autowired</div>
<div>
private WebApplicationContext restApplicationContext;</div>
</div>
<div>
<div>
<br /></div>
<div>
@Autowired</div>
<div>
private FilterChainProxy springSecurityFilterChain; </div>
</div>
<div>
<br /></div>
<div>
<div>
private MockMvc mockMvc;</div>
</div>
<div>
<br /></div>
<div>
...</div>
<div>
<br /></div>
@Before<br />
public void setUp() {<br />
mockMvc = MockMvcBuilders.webAppContextSetup(restApplicationContext)<br />
.addFilter(springSecurityFilterChain, "/*")<br />
.build();<br />
}<br />
<br />
@Test<br />
public void testCorrectUsernamePassword() throws Exception {<br />
String username = "vitali@vtesc.ca";<br />
String password = "password";<br />
<br />
ResultActions actions = mockMvc.perform(post("/user/register").header("Authorization", createBasicAuthenticationCredentials(username, password)));<br />
}<br />
}<br />
<br />
The test started to fail with the AuthenticationCredentialsNotFoundException as the root cause.<br />
The change that caused the failure was introduced in order to split request security filtering into 2 distinct filter chains. The existing configuration for securing RESTful calls with Basic authentication needed to be amended to add a separate handling of requests supporting the Web user interface of the application.<br />
That necessitated adding a second <security:http> configuration to the application-security.xml context:<br />
<br />
<div>
<!-- REST --></div>
<http pattern="/rest/**" entry-point-ref="basicAuthEntryPoint" authentication-manager-ref="restAuthManager"><br />
<div>
...</div>
<div>
</http></div>
<div>
<br /></div>
<!-- Web UI --><br />
<http pattern="/web/**" entry-point-ref="preAuthEntryPoint" authentication-manager-ref="webAuthManager"><br />
<custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" /><br />
<!-- Must be disabled in order for the webAccessDeniedHandler be invoked by Spring Security --><br />
<anonymous enabled="false"/><br />
<access-denied-handler ref="webAccessDeniedHandler"/><br />
</http><br />
<div>
<br /></div>
The pattern="/rest/**" attribute was also introduced at the same time to the original <http> configuration element.<br />
<br />
That is what ultimately caused the test to fail since the JUnit was not using Servlet path.<br />
It is important to note that Spring MVC Test Framework runs outside of a web container and has neither dependency nor is using the web.xml.<br />
When testing with MockMvc, it is not required to specify the context path or Servlet path when submitting requests to the controllers under test.<br />
For example, when testing this controller:<br />
<br />
@RequestMapping(value = "/user/register", method = RequestMethod.POST, headers = "accept=application/json,text/*", produces = "application/json")<br />
@PreAuthorize("hasPermission(null, 'ROLE_USER')")<br />
@ResponseBody<br />
public RegistrationResponse register(@RequestBody(required=false) UserDeviceLog userDeviceLog) {<br />
<div>
...</div>
<div>
it would be sufficient to send request only specifying the mapping:</div>
<div>
mockMvc.perform(post("/user/register").header("Authorization", createBasicAuthenticationCredentials(username, password)))</div>
<div>
<br /></div>
However, when access to the controllers is protected by Spring Security and the pattern is specified in the <security:http> configuration, the Spring MVC Test Framework will fully respect the processing flow failing requests that do not provide a correct Servlet path.<br />
<br />
Resolution:<br />
1. Specify a correct Servlet path in the request URL and also add the mapping by passing the path to the servletPath(String) method of the MockHttpServletRequestBuilder class:<br />
<br />
mockMvc.perform(post("<span style="background-color: yellow;">/rest</span>/user/register").<span style="background-color: yellow;">servletPath("/rest")</span>.header("Authorization", createBasicAuthenticationCredentials(username, password)));<br />
<br />
2. Configure the MockMvc instance with the security filter mapping that matches the pattern specified in the application-security.xml configuration:<br />
@Before<br />
public void setUp() {<br />
mockMvc = MockMvcBuilders.webAppContextSetup(restApplicationContext)<br />
.addFilter(springSecurityFilterChain, "<span style="background-color: yellow;">/rest</span>/*")<br />
.build();<br />
}<br />
<div>
<br /></div>
<end><br />
<br />Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0tag:blogger.com,1999:blog-5673137062674498091.post-89869034320922444582016-04-13T16:38:00.002-04:002016-04-13T16:38:28.320-04:00Various tips on Oracle SpatialWhen creating a spatial index on a table with SDO_GEOMETRY, one of the required parameters is LAYER_GTYPE.<br />
<br />
<h4>
How to find GTYPE of SDO_GEOMETRY objects in a table:</h4>
select sdo_geometry.get_gtype(geom), count(*) from map_data.zip_geom group by sdo_geometry.get_gtype(geom)<br />
/<br />
<br />Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0tag:blogger.com,1999:blog-5673137062674498091.post-89386972022533479042016-04-11T22:30:00.000-04:002016-04-11T22:30:07.143-04:00Configuring log4j to create a new log file at each Java program run.For running standalone Java programs, such as jobs, that use <a href="https://logging.apache.org/log4j/1.2/" target="_blank">Apache log4j logging</a>, it is often useful to have a separate log file per each program execution.<br />
The post covers a simple approach that can be used with a <code class="vtinline">FileAppender</code> by using a timestamp as part of the log file name injected from a system property.<br />
<br />
Two different samples are provided. One can be used when the Java program is launched directly from a shell (manually or via a scheduler) and the other when launching it as an Ant task.<br />
<br />
The log4j configuration is the same for both scenarios and is shown right below:<br />
<br />
<pre class="java" name="code"># A sample Log4j configuration demonstrating how to create a new log file
# at each program start.
# Created: Apr 6, 2016 by Vitali Tchalov
log4j.rootLogger=info, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout= org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %5p [%t] (%d) %c - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=logs/job_${log.timestamp}.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d [%t] %5p %c - %m%n
</pre>
<br />
The configuration uses a custom system property <code class="vtinline">log.timestamp</code> to append a unique (with a second precision) suffix to the log file name.<br />
<br />
The way the property is set depends on how the Java program is launched.<br />
<br />
<div class="vtsection">
Scenario 1 - when starting a plain regular Java program by directly invoking the java executable</div>
<br />
1. Add a system property in a static block of the main class (i.e. the launching class with the <code class="vtinline">main(String[])</code> method) prior to referencing any <code class="vtinline">Logger</code>.<br />
<br />
<pre class="java" name="code">static {
System.setProperty("log.timestamp",
new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()));
}
</pre>
<br />
Below is a complete class source code:<br />
<br />
<pre class="java" name="code">package com.forms2docx;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.Logger;
/**
* A sample class to demonstrate a technique to configure Log4j to create a new log file at each program run.
*
* To compile the sample program, specify the absolute path to a log4j.jar file, for example:
* javac -d bin -cp ".;./lib/log4j-1.2.17.jar;" ./com/forms2docx/*.java
*
* To run with the static block that programmatically adds the log.timestamp property:
* java -cp ".;./bin;./lib/log4j-1.2.17.jar;" com.forms2docx.Log4jNewFile
*
* To run with the log.timestamp property passed from the command line:
* java -cp ".;./bin;./lib/log4j-1.2.17.jar;" -Dlog.timestamp=$(date +"%Y%m%d_%H%M%S") com.forms2docx.Log4jNewFile
*
* @author Vitali Tchalov
*/
public class Log4jNewFile {
static {
System.setProperty("log.timestamp",
new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()));
}
private static final Logger logger = Logger.getLogger(Log4jNewFile.class);
public static void main(String[] args) {
logger.info(String.format("Job has started at %s.",
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
logger.info("The sample demonstrates how to configure Log4j to create a new file on every program run.");
}
}
</pre>
<br />
To execute this program, compile and run from a shell:<br />
<br />
<code class="vtinline">java -cp ".;./bin;./lib/log4j-1.2.17.jar;" com.forms2docx.Log4jNewFile</code><br />
<br />
Of course, a log4j jar file must reside on the classpath.<br />
<br />
If modifying the source is not possible or desirable for whatever reason, it is also possible to supply the system property on the command line, like this:<br />
<br />
<code class="vtinline">java -cp ".;./bin;./lib/log4j-1.2.17.jar;" -Dlog.timestamp=$(date +"%Y%m%d_%H%M%S") com.forms2docx.Log4jNewFile</code><br />
<br />
The command line above is for a UNIX system (e.g. Linux, Mac). It might be possible to adapt it for Windows too but formatting a date and time to a short format would be very cumbersome in Windows.<br />
<br />
<div class="vtsection">
Scenario 2 - starting a Java program (job) as an Ant task.</div>
<br />
These steps are required for launching a Java program as an Ant task:<br />
<br />
1. Include <code class="vtinline"><tstamp /></code> to the Ant build file<br />
2. Add the following to the java task:<br />
<code class="vtinline"><sysproperty key="log.timestamp" value="${DSTAMP}_${TSTAMP}" /></code><br />
<br />
Note, the <code class="vtinline">DSTAMP</code> and <code class="vtinline">TSTAMP</code> are standard variables defined by Ant.<br />
<br />
An example of an Ant build file to launch a Java program as an Ant task: (requires a log4j.jar file on the classpath as well as Ant in the PATH):<br />
<pre class="xml" name="code"><project name="Launch Java Ant task sample" basedir="." default="info">
<echo message="Launching Java Ant task sample..." />
<tstamp/>
<target name="info">
<echo message="The runJob Java task demonstrates creating a new log file at each run."/>
</target>
<target name="runJob" description="Demonstrates a new log file per each run.">
<java
classname="com.forms2docx.Log4jNewFile"
fork="true"
failonerror="true">
<jvmarg value='-Dlog4j.configuration=file:"${basedir}/log4j.properties"' />
<jvmarg value='-server' />
<sysproperty key="log.timestamp" value="${DSTAMP}_${TSTAMP}" />
<classpath>
<pathelement location="${basedir}/bin"/>
<fileset dir="${basedir}/lib">
<include name="*.jar" />
</fileset>
</classpath>
</java>
<echo message="Task completed."/>
</target>
</project>
</pre>
Note that by default, the <code class="vtinline">TSTAMP</code> is in "HHmm" format. When this precision is not sufficient, then a custom property with a required format can be added.<br />
For example:<br />
<pre class="xml" name="code"> <tstamp>
<format property="tstamp-sec" pattern="HHmmss"/>
</tstamp>
</pre>
<br />
Then the <code class="vtinline">sysproperty</code> in the <code class="vtinline">java</code> task would look like this:<br />
<br />
<pre class="xml" name="code"><sysproperty key="log.timestamp" value="${DSTAMP}_${tstamp-sec}" />
</pre>
/* --- end --- */Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0tag:blogger.com,1999:blog-5673137062674498091.post-41226873393114567782016-01-31T22:00:00.000-05:002016-02-01T13:12:39.267-05:00How to enable iOS app for iCloud Documents1. a) New app: create a new App ID in Member Center on Apple Developer website (<a href="https://developer.apple.com/" target="_blank">https://developer.apple.com/</a>). The account must have Agent or Admin role.<br />
<br />
- open Certificates, Identifiers & Profiles, select Identifiers<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-iy9fvrN3jqk/Vqu4xWx4mnI/AAAAAAAABHY/uqEQVEIy_3o/s1600/member-center-iOS-app-IDs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="441" src="http://4.bp.blogspot.com/-iy9fvrN3jqk/Vqu4xWx4mnI/AAAAAAAABHY/uqEQVEIy_3o/s640/member-center-iOS-app-IDs.png" width="640" /></a></div>
<br />
- click the + sign to create a new App ID.<br />
- App ID Description: enter a Name, for example - iCloudDriveExplorer<br />
- App ID Prefix: it defaults to the Team ID and is not editable<br />
- App ID Suffix: select the Explicit App ID option - it is a must for using iCloud. Example: net.samples.iCloudDriverExplorer<br />
- App Services: check the iCloud option and select either Compatible with Xcode 5 or Include CloudKit support (requires Xcode 6), whichever suits the needs. Note: the status initially will be set to Configurable with a yellow indicator - that is OK.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-W8agvK3TzBI/Vqu-QGfZunI/AAAAAAAABHo/1LnGlG2bKEc/s1600/member-center-iOS-app-IDs-iCloud-enable.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="579" src="http://1.bp.blogspot.com/-W8agvK3TzBI/Vqu-QGfZunI/AAAAAAAABHo/1LnGlG2bKEc/s640/member-center-iOS-app-IDs-iCloud-enable.png" width="640" /></a></div>
<br />
- click Continue and complete the App ID creation process.<br />
<br />
1. b) Existing app: Edit the App ID<br />
- check the iCloud box option and select either Compatible with Xcode 5 or Include CloudKit support (requires Xcode 6), whichever suits the needs. Note: the status initially will be set to Configurable with a yellow indicator - that is OK.<br />
<br />
2. In Xcode - create a new project or configure an existing project to enable iCloud Document entitlement.<br />
- select the project's target and open the Capabilities tab.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-6wC5I-GgTMc/VqvMejv-7OI/AAAAAAAABII/uVuT7F0TQzA/s1600/xcode-enable-icloud-on.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="196" src="http://4.bp.blogspot.com/-6wC5I-GgTMc/VqvMejv-7OI/AAAAAAAABII/uVuT7F0TQzA/s640/xcode-enable-icloud-on.tiff" width="640" /></a></div>
<br />
<br />
- expand the iCloud row and switch the iCloud <b>ON</b>. Xcode will create the project entitlement plist file, in this example named: iCloudDriveExplorer.entitlements<br />
<br />
The contents of the project entitlements file will look similar to this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><plist version="1.0"></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><dict></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <key>com.apple.developer.icloud-container-identifiers</key></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <array/></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <key>com.apple.developer.ubiquity-kvstore-identifier</key></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></dict></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></plist></span><br />
<br />
- check required iCloud services: Key-value storage, iCloud Documents and CloudKit, whatever is needed.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-6zmwk8iXcCk/VqvHNCqaBII/AAAAAAAABH4/XksynCyNxYg/s1600/xcode-enable-icloud.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="354" src="http://3.bp.blogspot.com/-6zmwk8iXcCk/VqvHNCqaBII/AAAAAAAABH4/XksynCyNxYg/s640/xcode-enable-icloud.tiff" width="640" /></a></div>
<br />
<b><br /></b>
When enabling iCloud Documents, Xcode will offer to use either the default container or custom containers. Configuring custom containers is a subject for another post.<br />
For the default container Xcode will add a container entitlement to the project entitlments file and will update the Provisioning Profile. After this step, the status indicator for iCloud in the Member Center will become green:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-IBFbeZiSo90/VqvUPRjuVGI/AAAAAAAABIY/VWC8PZaot3U/s1600/member-center-icloud-enabled-green.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="414" src="http://1.bp.blogspot.com/-IBFbeZiSo90/VqvUPRjuVGI/AAAAAAAABIY/VWC8PZaot3U/s640/member-center-icloud-enabled-green.png" width="640" /></a></div>
<br />
<br />
After Xcode adds containers to the project entitlement file, it will be similar to this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><plist version="1.0"></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><dict></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <key>com.apple.developer.icloud-container-identifiers</key></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <array></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <string>iCloud.$(CFBundleIdentifier)</string></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </array></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <key>com.apple.developer.icloud-services</key></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <array></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <string>CloudDocuments</string></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </array></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <key>com.apple.developer.ubiquity-container-identifiers</key></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <array></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <string>iCloud.$(CFBundleIdentifier)</string></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </array></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <key>com.apple.developer.ubiquity-kvstore-identifier</key></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></dict></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></plist></span><br />
<br />
<b>Important:</b><br />
Enabling iCloud for an app requires an Xcode Developer Account with Agent or Admin role.<br />
Even though Xcode allows to have multiple Developer Accounts (Xcode > Preferences > Accounts) and prompts to choose the account with which to enable iCloud, it may fail to create a container entitlement:<br />
Add the "iCloud containers" entitlement to your App ID.<br />
<br />
In this case Xcode will offer the Fix it option. However, running the Fix will not prompt for the Developer Account and may fail if the account Xcode choses to run with does not have Agent or Admin role.<br />
One workaround is to remove, temporarily, other accounts from Xcode and only leave the Admin (or Agent) account. The other accounts can be exported into a file (Xcode > Preferences > Accounts > select Apple ID then click the Setting icon on the bottom left > Export Developer Accounts).<br />
When iCloud configuration complete, these accounts can be easily imported back.<br />
<b><br /></b>
<b>Update:</b><br />
In later versions of Xcode, for example 7.2, it is also possible to create and enable iCloud entitlements entirely from within Xcode. As long as the Developer Account has Agent or Admin role, Xcode will create App ID automatically. It will also modify the Provisioning Profile to enable iCloud service when the iCloud capability is switched on. And it will create entitlements for the default iCloud container. Manually creating App ID and enabling it for iCloud via Member Center is no longer the only option.<br />
<br />
<br />Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com2tag:blogger.com,1999:blog-5673137062674498091.post-61664233093020543502014-10-17T22:41:00.000-04:002014-10-20T09:59:22.303-04:00RestKit install - RKValueTransformers file not found<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Adding the <a href="https://github.com/RestKit/RestKit" target="_blank">RestKit</a> framework to an Xcode project manually, i.e. without using CocoaPods, results in project build errors similar to these:</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Compile RKEntityMapping.m</span><br />
<span style="color: red; font-family: Trebuchet MS, sans-serif;">'RKValueTransformers.h' file not found</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"> In file included from /.../RestKit-0.23.3/Code/CoreData/RKEntityMapping.m:21</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"> In file included from /.../RestKit-0.23.3/Code/CoreData/RKEntityMapping.h:22</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Compile RKManagedObjectImporter.m</span><br />
<span style="color: red; font-family: Trebuchet MS, sans-serif;">'RKValueTransformers.h' file not found</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"> In file included from /.../RestKit-0.23.3/Code/CoreData/RKManagedObjectImporter.m:26</span><br />
<div>
<span style="font-family: 'Trebuchet MS', sans-serif;">0.23.3/Code/CoreData/RKMapperOperation.h:22</span></div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Up to and including version 0.20.3, adding the RestKit framework </span><span style="font-family: 'Trebuchet MS', sans-serif;">downloaded as a source zip file from <a href="https://github.com/RestKit/RestKit/releases" target="_blank">GitHub</a> required a few simple steps (todo: link) and </span><span style="font-family: Trebuchet MS, sans-serif;">worked easily on several projects.</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Following the same procedure to add version 0.23.3 resulted in the errors shown above. </span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Both files, i.e. RKValueTransformers.h and RKValueTransformers.m, are still referenced from the RestKit.xcodeproj but are not bundled into the zipped source.</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">It turns out that beginning with version 0.22.0, these 2 files were extracted from RestKit project into its own project on GitHub: <a href="https://github.com/RestKit/RKValueTransformers" target="_blank">https://github.com/RestKit/RKValueTransformers</a></span><br />
<span style="font-family: Trebuchet MS, sans-serif;">The project needs to be downloaded separately (i.e. when not using CocoaPods for installation).</span><br />
<span style="font-family: Trebuchet MS, sans-serif;">The two files can be simply copied into this directory under the RestKit:</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>RestKit-0.23.3/Vendor/RKValueTransformers</b></span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Unfortunately, that does not solve the whole problem. Apparently, packaging of the source code was changed and no longer includes dependencies such as AFNetworking, SOCKit and others.</span><br />
<span style="font-family: Trebuchet MS, sans-serif;">So, if you persist in your stubbornness (as does this author) and still prefer to integrate RestKit into your project without CocoaPods, you're facing a very daunting option: download all dependencies manually and add them to the sub-directories inside the RestKit-0.23.3/Vendor.</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">Luckily, there is a faster way (only takes few minutes): the trick is to use CocoaPods to bring all dependencies into a helper project and then simply copy files into the target .</span><br />
<br />
<ul>
<li><span style="font-family: 'Trebuchet MS', sans-serif;">create a new simple project in Xcode. The template does not matter, Single View Application is fine. Project name just for example: RestKitPodsInstall</span></li>
<li><span style="font-family: Trebuchet MS, sans-serif;">install CocoaPods (if the Mac does not have the package already):</span></li>
</ul>
<span style="font-family: 'Courier New', Courier, monospace;"> sudo gem install cocoapods</span><br />
<ul>
<li><span style="font-family: Trebuchet MS, sans-serif;">cd into the project directory, i.e. the directory that contains the Xcode project file (e.g.</span> <span style="font-family: Courier New, Courier, monospace;">RestKitPodInstall.xcodeproj</span><span style="font-family: Trebuchet MS, sans-serif;">)</span></li>
<li><span style="font-family: Trebuchet MS, sans-serif;">create a Podfile:</span></li>
</ul>
<span style="font-family: Courier New, Courier, monospace;">vi Podfile</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<div style="font-size: 11px;">
<span style="font-family: Courier New, Courier, monospace; font-size: small;">platform :ios, '5.0'</span></div>
<span style="font-family: Courier New, Courier, monospace;">pod 'RestKit', '~> 0.23.3'</span><br />
<div style="font-family: Menlo; font-size: 11px;">
<br /></div>
<span style="font-family: Trebuchet MS, sans-serif;">(change the version to the latest available or whatever is needed)</span><br />
<div style="font-family: Menlo; font-size: 11px;">
<br /></div>
<ul>
<li><span style="font-family: Trebuchet MS, sans-serif;">install RestKit into the helper project by running:</span></li>
</ul>
<span style="font-family: Courier New, Courier, monospace;">pod --verbose install</span></div>
<div>
<div style="color: #afad24; font-family: Menlo; font-size: 11px;">
<br /></div>
<span style="font-family: Trebuchet MS, sans-serif;">It should finish with something like this:</span><br />
<div style="color: #afad24; font-family: Menlo; font-size: 11px;">
<br /></div>
<div style="color: #afad24; font-family: Menlo; font-size: 11px;">
Integrating client project</div>
<div style="font-family: Menlo; font-size: 11px; min-height: 13px;">
<br /></div>
<div style="color: #34bd26; font-family: Menlo; font-size: 11px;">
[!] From now on use `RestKitPodInstall.xcworkspace`.</div>
<div style="font-family: Menlo; font-size: 11px; min-height: 13px;">
<br /></div>
<div style="color: #34bd26; font-family: Menlo; font-size: 11px;">
Integrating target `Pods` (`RestKitPodInstall.xcodeproj` project)</div>
<ul>
<li><span style="font-family: Trebuchet MS, sans-serif;">copy, one by one, content of sub-directories in the Pods directory of the helper project to the target project. Keep in mind that the RestKit source already has placeholder directories for dependencies under the </span><span style="font-family: Courier New, Courier, monospace;">Vendor</span><span style="font-family: Trebuchet MS, sans-serif;"> subfolder. The example below assumes that a manually downloaded </span><span style="font-family: Courier New, Courier, monospace;">RestKit-0.23.3</span><span style="font-family: Trebuchet MS, sans-serif;"> source code was placed under the </span><span style="font-family: Courier New, Courier, monospace;">Library</span><span style="font-family: Trebuchet MS, sans-serif;"> directory in the target project named Algonquin. The current directory is the project directory of the helper project. (Also note the / at the end of the copied source directory</span>)</li>
</ul>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">mac:RestKitPodInstall vit$ cp -R Pods/AFNetworking/ /Users/vit/iOS-Projects/Algonquin/Algonquin/Library/RestKit-0.23.3/Vendor/AFNetworking</span><br />
<div style="font-family: Menlo; font-size: 11px;">
<br /></div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">mac:RestKitPodInstall vit$ cp -R Pods/</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">ISO8601DateFormatterValueTransformer</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/ /Users/vit/iOS-Projects/Algonquin/Algonquin/Library/RestKit-0.23.3/Vendor/</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">ISO8601DateFormatterValueTransformer</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">mac:RestKitPodInstall vit$ cp -R Pods/</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">RKValueTransformers</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/ /Users/vit/iOS-Projects/Algonquin/Algonquin/Library/RestKit-0.23.3/Vendor/</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">RKValueTransformers</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">mac:RestKitPodInstall vit$ cp -R Pods/</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">SOCKit</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/ /Users/vit/iOS-Projects/Algonquin/Algonquin/Library/RestKit-0.23.3/Vendor/</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">SOCKit</span></div>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">mac:RestKitPodInstall vit$ cp -R Pods/</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">TransitionKit</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/ /Users/vit/iOS-Projects/Algonquin/Algonquin/Library/RestKit-0.23.3/Vendor/</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">TransitionKit</span></div>
</div>
<br />
<span style="font-family: Trebuchet MS, sans-serif;">After all copying is done, the target project should have the structure similar to this:</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<code class="tr_bq">
Algonquin (it's the target project)<br />
| Algonquin<br />
| | main.m <br />
| | VTAppDelegate.h<br />
| | (other source files)<br />
| | Library<br />
| | | RestKit-0.23.3<br />
| | | | RestKit.xcodeproj<br />
| | | | Code<br />
| | | | Resources<br />
| | | | (other files)<br />
| | | | Vendor<br />
| | | | | AFNetworking<br />
| | | | | | AFNetworking<br />
| | | | | | | AFHTTPClient.h<br />
| | | | | | | AFHTTPClient.m<br />
| | | | | | | (other source files)<br />
| | | | | | LICENCE<br />
| | | | | | README.md<br />
| | | | | RKValueTransformers<br />
| | | | | | Code<br />
| | | | | | | RKValueTransformers.h<br />
| | | | | | | RKValueTransformers.m<br />
| | | | | | LICENSE<br />
| | | | | | README.md <br />
| | | | | (rest of dependencies) <br />
| | | (other libraries)<br />
| Algonquin.xcodeproj<br />
| AlgonquinTests</code>
<br />
<br />
<span style="font-family: Trebuchet MS, sans-serif;">The target project should not be opened in Xcode during this procedure. When the copying complete, open the target project in Xcode. The project should compile without failures (assuming of course that RestKit was already previously configured and that is just a replacement to a newer version). </span></div>
Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com1tag:blogger.com,1999:blog-5673137062674498091.post-23794222881936202802014-08-22T21:28:00.000-04:002014-08-22T21:28:00.394-04:00Ehcache CacheManager with same name already exists in the same VMkeys: Java, Ehcache, CacheManager name, multiple configurations<br />
<br />
<div class="vtsection">
Straight to the point:</div>
<br />
Explicitly providing a <code class="vtinline">CacheManager</code> <b>name</b> in an <a href="http://ehcache.org/" target="_blank">Ehcache</a> configuration file allows to avoid the <span style="color: #660000;">"CacheManager with same name already exists in the same VM"</span> error after upgrading to Ehcache version 2.5 and later.
<br />
The CacheManager name should be specified in each Ehcache config file via the <code class="vtinline">name</code> attribute of the top-level <code>ehcache</code> element, for example:<br />
<br />
<code>ehcache.xml</code>
<br />
<pre class="brush:xml"><ehcache <b>name="http-filter-cache"</b>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcahce.xsd">
<defaultCache />
</ehcache>
</pre>
This works regardless whether a singleton or multiple instances of CacheManager are created.<br />
<br />
<div class="vtsection">
In detail:</div>
<br />
<a href="http://ehcache.org/" target="_blank">Ehcache</a> is a widely used open-source caching solution for enterprise Java applications.<br />
Most known examples, perhaps arguably, would be using Ehcache as a <a href="http://ehcache.org/documentation/hibernate/index" target="_blank">second-level Hibernate cache</a> and <a href="http://camel.apache.org/cache.html" target="_blank">the cache implementation in Apache Camel</a>.<br />
Version 2.5 was enhanced with a new feature called <a href="http://ehcache.org/documentation/arc/index" target="_blank">Automatic Resource Control</a>. The ARC (finally) allowed to specify heap and disk allocations in bytes rather than in elements (as well as for Off Heap storage).<br />
<br />
Problem:<br />
After upgrading a Java web application to take advantage of the new version, we encountered a problem that manifested in failures of numerous JUnit tests. Launching the web application also started to fail.<br />
<br />
Examining log files revealed the following error message:<br />
<br />
<div class="note">
CacheManager with same name already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:<br />
<br />
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary<br />
2. Shutdown the earlier cacheManager before creating new one with same name.</div>
<br />
The application included 2 Ehcache configuration files each containing a default cache definition as well as several other named caches. At first, a suspicion was that the problems were caused by having more than one <b>default cache (</b>each file contains a default cache definition<b>)</b>. Since the default caches are unnamed, there might have been a collision. That's however proved to be a totally wrong lead.<br />
<br />
Proceeding to examine the source code of <code class="vtinline">net.sf.ehcache.CacheManager</code> class, we came across this javadoc comment in class constructors:<br />
<br />
<div class="note">
Since 2.5, every newly created CacheManager is registered with its name (uses a default name if unnamed), and trying to create multiple CacheManager with same names (or multiple unnamed CacheManagers) is not allowed and throws an exception.</div>
<br />
Looking further into the source code and stepping in with the debugger, we discovered that CacheManager now maintains a static <code class="vtinline">Map<String, CacheManager></code> class variable to store every instance of the class created in the JVM using the name specified in a configuration as the key (the map is named <code>CACHE_MANAGERS_MAP</code> as of version <code>ehcache-core 2.6.9</code>).<br />
<br />
All constructors and the factory methods utilize the map to return a CacheManager object according to the specs. The CacheManager provides two kinds of instantiation modes: creating a new instance on each call or returning an existing object (singleton). (More on CacheManager creation modes can be found on a <a href="http://ehcache.org/documentation/user-guide/concepts">Ehcache website</a>).<br />
<br />
<b>Regardless</b> of the creation mode, i.e. instance or singleton, the CacheManager name must be unique.<br />
<br />
Surprisingly, considering that the change is quite well documented, the Ehcache documentation does not spell out, at least not readily, <b>how to assign a name</b> to a <code>CacheManager</code> instance.<br />
The answer was found in the <a href="http://ehcache.org/ehcache.xsd">ehcache.xsd</a> schema that specifies the optional <code class="vtinline">name</code> attribute for the <code>ehcache</code> element:<br />
<pre class="brush:xml"><xs:schema>
<xs:element name="ehcache">
<xs:complexType>
<b><xs:attribute name="name" use="optional"/></b>
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="0" ref="diskStore"/>
...
</xs:sequence>
...
</pre>
When the <code>name</code> attribute is specified for the the top-level <code>ehcache</code> element, a <code>CacheManager</code> constructor will use its value as the name for the CacheManger instance and as the key when registering the object in the static <code>CACHE_MANAGERS_MAP</code> map. Otherwise, i.e. when the name attribute is omitted, CacheManager will use a default value, <code>__DEFAULT__</code>, as the name. If the app is designed to use a single ehcache configuration, it will not cause any trouble. However, there are cases when it's preferable to use multiple cache configuration files. In which case it will result in the error when the name attribute is not used.<br />
<br />
To avoid the problem, each Ehcache configuration should specify a name. The fragment from a configuration file below is an example:
<br />
<pre class="brush:xml"><ehcache <b>name="http-filter-cache"</b> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocaton="ehcache.xsd">
<!-- CacheManager configuration
(omitted from the sample)
/>
</ehcache>
</pre>
And in conclusion, a friendly suggestion to the Ehcache development team: maybe the name attribute should be made <b>mandatory</b> rather than optional to avoid the problem described in this post.<br />
<br />Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0tag:blogger.com,1999:blog-5673137062674498091.post-44099098724498597242014-08-05T22:37:00.000-04:002016-04-11T15:09:18.690-04:00Spring Framework Annotation-based ConfigurationWith seemingly en masse transition of Java Spring framework users to annotation-based configuration, it sometimes can be quite frustrating to find yourself in a corner when a context configuration easily achievable with XML, can not be realized via annotations.<br />
These are 2 examples:<br />
<br />
<ul>
<li>configuring multiple service instances of the same class (not the prototype scope kind of multiplicity).</li>
<li>auto wiring of a service implementation based on a configuration parameter.</li>
</ul>
<div class="vtsection">
The first case:</div>
<br />
Suppose there is a need to have 2 service beans of the <b>same service implementation</b>. (Of course, to have sense, the bean instances need to be distinct, for example by setting their instance variables to different values).<br />
With an XML config, that can be easily achieved by declaring 2 beans with different ID values, for example:<br />
<pre name="code" class="xml"><bean class=“DocumentServiceImpl” id=“documentService”/>
<bean class=“DocumentServiceImpl” id=“loggingDocumentService”>
<property name=“shouldLogRequests” value=“true”/>
</bean>
</pre>
<br />
Then, these beans can be configured for injection either in XML via the ref parameter:<br />
<br />
<pre name="code" class="xml"><bean class=“DocumentServiceController”>
<property name=“documentService” ref=“documentService”/>
<property name=“loggingDocumentService” ref=“loggingDocumentService”/>
</bean>
</pre>
<br />
Or alternatively, even autowiring like this:<br />
<br />
<pre name="code" class="java">public class DocumentServiceController {
@Autowired
@Qualifier("baseDocumentService")
private DocumentService baseDocumentService;
@Autowired
@Qualifier("loggingDocumentService")
private DocumentService loggingDocumentService;
}
</pre>
<br />
The same simply cannot be done via type-level annotations (or, at least not as easily).<br />
This is an annotation based configuration similar to the XML above:<br />
<pre name="code" class="java">@Service
public class BaseDocumentService implements DocumentService {
}
</pre>
<br />
However, since the <code class="vtinline">@Service</code> annotation takes only a single String parameter, there is simply no way to instantiate a second bean of the same class assigning it a different name or id.<br />
<br />
Even though this seems to be a conscious design choice of Spring framework architects (see below; note, the emphasis is the author's), it still can be maddeningly frustrating while looking for a solution.<br />
<br />
From a Spring doc at <a href="http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s11.html" target="_blank">4.11.3 Fine-tuning annotation-based autowiring with qualifiers</a><br />
<div class="note">
For a fallback match, the bean name is considered as a default qualifier value. This means that the bean may be defined with an id "main" instead of the nested qualifier element, leading to the same matching result. However, note that while this can be used to refer to specific beans by name, <strong>@Autowired is fundamentally about type-driven injection with optional semantic qualifiers.</strong> This means that qualifier values, even when using the bean name fallback, always have narrowing semantics within the set of type matches; <strong>they do not semantically express a reference to a unique bean id.</strong> Good qualifier values would be "main" or "EMEA" or "persistent", expressing characteristics of a specific component - independent from the bean id (which may be auto-generated in case of an anonymous bean definition like the one above).
</div>
<br />
So, to comply with this design, the following approach should be used to achieve the goal of having multiple service bean instances of the same class:<br />
<br />
<ul>
<li>Create a new implementation that extends the base service class.</li>
<li>Define a post construct method in this new class that sets parameters that would make a second instance to be different.</li>
</ul>
<br />
<pre name="code" class="java">@Service(“loggingDocumentService”)
public class LoggingDocumentService extends DocumentServiceImpl {
@PostConstruct
public void postConstruct() {
super.setShouldLogRequests(true);
}
}
</pre>
<br />
Okey, that is not too high price for switching to annotations-based configuration. It actually may promote a better object design, i.e. using subclassing to extend the behaviour of a class rather than using an instance variable and if-else statements for controlling its logic (though it’s not always possible).<br />
<br />
<div class="vtsection">
Let’s now look at the second scenario.</div>
Under this scenario, there are two different implementations of the <b>same interface </b>(see example below).<br />
Suppose there is also a controller that should be configured via an environment property to use a particular service implementation. For instance, setting an environment configuration property, say <code class="inline">document.service.caching.enabled=true</code>, should result in Spring injecting the service implementation that provides document caching capabilities.<br />
<br />
<pre name="code" class="java">public class BaseDocumentService implements DocumentService {
}
</pre>
<pre name="code" class="java">public class CachingDocumentService extends BaseDocumentService {
}
public class DocumentServiceController {
private DocumentService documentService;
}
</pre>
<br />
When using XML configuration, this can be easily achieved by, by way of illustration, using a <a href="http://docs.spring.io/spring/docs/3.0.x/reference/expressions.html" target="_blank">SpEL</a> expression:<br />
<br />
<pre name="code" class="xml"><bean class="BaseDocumentService" id="baseDocumentService" />
<bean class="CachingDocumentService" id="cachingDocumentService" />
<bean class="DocumentServiceController" id="documentServiceController">
<property name="documentService" ref="#{'${document.service.caching.enabled}'=='yes' ? 'cachingDocumentService' : 'baseDocumentService'}" />
</bean>
</pre>
<br />
With annotations-based Spring configuration, we would need to annotate an instance variable in the controller using the @Qualifier annotation:<br />
<br />
<pre name="code" class="java">@Controller
public class DocumentServiceController {
@Autowired
@Qualifier("documentService")
private DocumentService documentService;
}
</pre>
<br />
Had the @Qualifier annotation accepted property placeholders, that would be the end of the story.<br />
Unfortunately, Spring architects decided not to resolve placeholders in the @Qualifier. Neither there is support for SpEL expressions.<br />
Good news is that it's still possible to solve this task, bad news is that the solution is quite verbose.<br />
<br />
First, we would need to implement a <a href="http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/beans/factory/FactoryBean.html" target="_blank">FactoryBean<T></a> interface:<br />
<br />
<pre name="code" class="java">@Component("documentServiceFactory")
@DependsOn({"baseDocumentService", "cachingDocumentService"})
public class DocumentServiceFactory implements FactoryBean<DocumentService> {
@Autowired
@Value("${document.service.caching.enabled}")
private boolean enableDocumentCaching;
@Autowired
@Qualifier("baseDocumentService")
private DocumentService baseDocumentService;
@Autowired
@Qualifier("cachingDocumentService")
private DocumentService cachingDocumentService;
@Override
public DocumentService getObject() throws Exception {
return enableDocumentCaching ? cachingDocumentService : baseDocumentService;
}
@Override
public Class<?> getObjectType() {
return DocumentService.class;
}
}
</pre>
<br />
Second, the qualifier on the service reference in the controller needs to specify the factory bean rather than a service bean. Note though, the type of the reference remains of the service interface (i.e. not of the factory):<br />
<br />
<pre name="code" class="java">@Controller
public class DocumentServiceController {
@Autowired
@Qualifier("documentServiceFactory")
private DocumentService documentService;
}
</pre>
<br />
A drawback of this solution is that at runtime there still going to be 2 beans in the memory while only one will be served by the factory to the controller. However, considering that service bean implementations should not take up too much memory since they need to be thread-safe (i.e. limited number of instance variables), that drawback should not represent a tangible problem.<br />
And forerunning a potential question: Why would it be desired to have an <b>annotation-only</b> Spring configuration? True, typically in medium and large applications it's not practical. But in small programs, like a job or utility, the program becomes tidy when everything is configured through annotations. The other main usage is for JUnit tests. It's impractical to bring up the whole context of a large application for running a JUnit, so instead of creating a myriad of test-specific contexts, it's much productive to have JUnits fully configurable via annotations.<br />
<br />Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0tag:blogger.com,1999:blog-5673137062674498091.post-70720154312867612132014-01-04T21:30:00.000-05:002014-01-06T08:30:30.066-05:00Xcode Build for iOS - conditional copy of resource files based on Build Configuration<div style="font-family: Menlo; font-size: 12px;">
<b>A brief: </b>Use Run Script build phase in Xcode to selectively copy resource files, such as Settings.bundle, security certificates, etc., depending on the build configuration, e.g. Debug or Release.<br />
How-To: Project Navigator: select a project, select a target, select Build Phases tab; menu: Editor > Add Build Phase > Add Run Script Build Phase.<br />
<br />
<b>In detail:</b><br />
Couple days ago I needed to make a minor change to how we compile/build our <b>iOS</b> app. The app has a few settings but all of them for development only. While preparing a submission to Apple, we wanted to remove the app from the <i>Settings</i> view on iPad completely. The challenge was to keep the settings for developer builds. This proved to be a bit more difficult than expected. Hence, a post to document how it can be done as well as a few things learned about Build Project settings, Targets, Build Configurations, Schemes, logs etc. in <b>Xcode </b>(v5). </div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
For an iOS app to have an entry to the standard Settings view, the app needs to include a <b>Settings.bundle</b> file (which is actually a directory on the file system, by the way). When the file is added to a <i>project</i> (any file for that matter actually), Xcode allows to selectively include it into the project's <i>targets</i>. Normally, an Xcode project would have the main target (named after the app) and a test target. So, one way to conditionally include a file, Settings.bundle in my case, into the build is to duplicate the main <i>target</i> and use that duplicated target for developer builds only. For example, let's say our app name is iStockFutures and by default the main target is iStockFutures. We could've duplicated that target into iStockFutures-Dev and kept the Settings.bundle file as a member of the iStockFutures-Dev target only. A sample screenshot is shown below.</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-qrg9xDBGbbU/UqTe9UGxozI/AAAAAAAAAMc/pV1e_0erFTU/s1600/xcode-duplicate-target-cropped.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-qrg9xDBGbbU/UqTe9UGxozI/AAAAAAAAAMc/pV1e_0erFTU/s1600/xcode-duplicate-target-cropped.tiff" height="332" width="640" /></a></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
That would accomplish the task. But there is drawback - having multiple targets means that developers have to be mindful when adding new files (<b>any</b> new file) and better not forget to include it into both targets. When running the app in Xcode, the dev target then should be used but when committing code to a build server, it had better be tested on both targets. Needless to say, my development team was not thrilled on that prospect. </div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
Luckily, there is a more transparent way:</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
The build process in Xcode includes multiple phases. One of them is <i><b>Copy Bundle Resources</b></i>. The phase has a list of resource files to copy. When the Settings.bundle was added to the project, Xcode automatically included it into that list. Unfortunately, Xcode 5 does not allow to have multiple versions of the list based on Configuration, e.g. Release or Debug. Not sure why Apple didn't do it, after all, such capability exists and is widely used in <i>Build Settings</i>. Anyway, this can be easily achieved by using a <b><i>Run Script</i></b> phase. <a href="https://developer.apple.com/library/ios/recipes/xcode_help-project_editor/Articles/AddingaRunScriptBuildPhase.html#//apple_ref/doc/uid/TP40010155-CH11-SW1" target="_blank">Run Script</a> is a feature in Xcode that allows to execute a custom script while building a <i>Product (i.e. an App)</i>. Multiple script languages are supported (see the link above) but since all what we need to do is to copy a file, ah, sorry, I meant a directory, we just going to use the standard <i>/bin/sh</i>.<br />
To create a Run Script phase, select the project in the Project Navigator, then make sure that a target is selected (otherwise the menu will be greyed out/disabled).<br />
<div>
Then use the <i>Editor</i> menu to add a Run Script phase: Editor > Add Build Phase > Add Run Script Build Phase</div>
<br />
<div style="color: #d12f1b;">
</div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Menlo; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;">
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="margin: 0px;">
<br /></div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-H-friWSFFuQ/Uqc8-RrMU4I/AAAAAAAAAM4/dYo6vSIOZXI/s1600/add-run-script-build-phase-cropped.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-H-friWSFFuQ/Uqc8-RrMU4I/AAAAAAAAAM4/dYo6vSIOZXI/s1600/add-run-script-build-phase-cropped.tiff" height="284" width="640" /></a></div>
<br />
<br /></div>
<div>
<div style="font-family: Menlo; font-size: 12px;">
When it's added, expand the Run Script phase and add this script (modify it as needed, of course) that copies Settings.bundle if build is run in Debug configuration:</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div>
<div style="color: #d12f1b;">
<span style="font-family: Courier New, Courier, monospace;"><span style="color: black;">echo </span>"Checking configuration to determine whether to copy Settings.bundle: CONFIGURATION=$CONFIGURATION"</span></div>
<div style="color: #d12f1b;">
<span style="font-family: Courier New, Courier, monospace;"><span style="color: black;">if [ </span>"$CONFIGURATION"<span style="color: black;"> == </span>"Debug"<span style="color: black;"> ]; then</span></span></div>
<div style="color: #d12f1b;">
<span style="font-family: Courier New, Courier, monospace;"><span style="color: black;">echo </span>"Copying ${SRCROOT}/${PRODUCT_NAME}/Settings.bundle directory to ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app"</span></div>
<div style="color: #d12f1b;">
<span style="font-family: Courier New, Courier, monospace;">cp -R ${SRCROOT}/${PRODUCT_NAME}/Settings.bundle ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Settings.bundle</span></div>
<div style="color: #d12f1b;">
<span style="font-family: Courier New, Courier, monospace;"><span style="color: black;">echo </span>"Settings.bundle directory has been copied."</span></div>
<span style="font-family: Courier New, Courier, monospace;">else</span><br />
<div style="color: #d12f1b;">
<span style="font-family: Courier New, Courier, monospace;"><span style="color: black;">echo </span>"Skipped copying Settings.bundle - not required for $CONFIGURATION configuration."</span></div>
<span style="font-family: 'Courier New', Courier, monospace;">fi</span></div>
<div>
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
Now, remove the Settings.bundle from the target, iStockFutures in the sample app.<br />
<blockquote class="tr_bq">
<i style="background-color: white;">(There are at least 2 ways to do that - either edit the list under Copy Bundle Resources or select Settings.bundle in Project Navigator and uncheck all targets in the File Inspector's Target Membership [View > Utilities > Show File Inspector]).</i></blockquote>
</div>
<div style="font-family: Menlo; font-size: 12px;">
This is important:</div>
<div style="font-family: Menlo; font-size: 12px;">
<br />
<ul>
<li>Run <i>Product > Clean</i> before running <i>Product > Build</i>, otherwise the Settings.bundle copied before will still be packaged into the app.</li>
<li>Uninstall the app from the device and/or simulator - <b>that will remove</b> the app entry from the Settings app.</li>
</ul>
</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
Also, if you played with the solution presented first, i.e. a dev target, remember to remove that dev target.</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
Let's build the product in <i>Debug</i> configuration first and look into Xcode build log files to verify the script is being run.</div>
<div style="font-family: Menlo; font-size: 12px;">
<br />
<b>Hint:</b> Where to find Xcode build logs: from the menu: View > Navigators > Show Log Navigator<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="http://1.bp.blogspot.com/-c8SN_T8fyM4/Uqsg9Ec-wmI/AAAAAAAAANI/0uLoYcj-J3c/s1600/xcode-log-navigator.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-c8SN_T8fyM4/Uqsg9Ec-wmI/AAAAAAAAANI/0uLoYcj-J3c/s1600/xcode-log-navigator.tiff" height="534" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Select the default group and the <i>All Messages</i> option: </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-VZZjW6gx-qw/Uqsz6wXPo2I/AAAAAAAAANk/gdx2MGFZ_fQ/s1600/xcode-build-debug-log.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-VZZjW6gx-qw/Uqsz6wXPo2I/AAAAAAAAANk/gdx2MGFZ_fQ/s1600/xcode-build-debug-log.tiff" height="242" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
This is it for building in Debug configuration.<br />
<br />
To fully complete the work we need to verify it builds correctly in Release configuration as well. It can be done by running a command-line build configured to Release (a default configuration setting on the Project) on the team's CI (Continuous Integration) server. But of course a better approach is to test it on a developer's Mac beforehand.<br />
An Xcode's feature called <b>Scheme</b> comes handy here (<a href="https://developer.apple.com/library/ios/featuredarticles/XcodeConcepts/Concept-Schemes.html" target="_blank">more info</a>). It allows to maintain multiple sets of targets each configured to a specific Build Configuration, i.e. Debug or Release.<br />
<br />
A new scheme can be created via the Product > Scheme menu.<br />
<br />
Select Product > Scheme > Edit Scheme…, then Duplicate one of the existing schemes (1) and change the Build Configuration to Release (2):<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-7hosjuxM5BQ/UsbgODXzpfI/AAAAAAAAAPA/EUgWO4FfrSc/s1600/xcode-scheme-edit.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-7hosjuxM5BQ/UsbgODXzpfI/AAAAAAAAAPA/EUgWO4FfrSc/s1600/xcode-scheme-edit.tiff" height="436" width="640" /></a></div>
</div>
<div style="font-family: Menlo; font-size: 12px;">
<br />
<br />
After creating and configuring a new scheme, make it active by selecting it in Product > Scheme > iStockFutures-Release menu.<br />
Build the app by running Product > Clean and Product > Build. When completed, check the build log file.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-9eNvhTLZ6qk/Uqsz683YWeI/AAAAAAAAANY/Uvl8fMeuKag/s1600/xcode-build-log-release.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-9eNvhTLZ6qk/Uqsz683YWeI/AAAAAAAAANY/Uvl8fMeuKag/s1600/xcode-build-log-release.tiff" height="292" width="640" /></a></div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Menlo; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;">
</div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Menlo; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;">
<div style="margin: 0px;">
That should be all.</div>
</div>
</div>
<div style="font-family: Menlo; font-size: 12px;">
<br />
Ok, that's not been very complicated, why it took more time than expected? That's because a bulk went into attempting to figure out and tinkering with Xcode environment variables. </div>
<div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
Here is a couple things that helped.</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
How to print all Xcode environment variables:</div>
<div style="font-family: Menlo; font-size: 12px;">
Open a Terminal window, change the directory to the project directory, i.e. the one that contains <project_name>.xcodeproj file and run this command:</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<span style="font-family: Courier New, Courier, monospace;">xcodebuild -project iStockFutures.xcodeproj -target "iStockFutures" -showBuildSettings > iStockFutures-build-settings.txt</span></div>
<div style="font-family: Menlo; font-size: 12px;">
<br />
All Xcode settings will be saved in the specified file. Replace iStockFutures with your project, of course.</div>
<div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
Official Xcode Build Settings Reference doc from Apple:</div>
<div style="font-family: Menlo; font-size: 12px;">
<br />
<a href="https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html" target="_blank">https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html</a></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
And a last tip - for successful builds the log file does not show too many details. However, add a faulty Run Script build phase, something like this for example:</div>
<div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<span style="font-family: Courier New, Courier, monospace;">cp ${SRCROOT}/file-that-doesnot-exist.txt ${BUILT_PRODUCTS_DIR}/file-that-doesnot-exist.txt</span></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
Build fails and the log file can be expanded to see quite a bit of details; it might be handy in understanding how the build works:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-_tT_tT8prZI/UsbsKO7RRKI/AAAAAAAAAPQ/dyKnoDuV1Kg/s1600/xcode-run-script-log-fail.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-_tT_tT8prZI/UsbsKO7RRKI/AAAAAAAAAPQ/dyKnoDuV1Kg/s1600/xcode-run-script-log-fail.tiff" height="298" width="640" /></a></div>
<br />
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
<b>Conclusion</b></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
By the way, the Run Script approach can be used to copy not only Settings.bundle but other environment-specific files. For example, we also used the script to copy Development and UAT/Production security certificates that we use for 2-way SSL/TLS authentication.</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
</div>
</div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
<br />
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
<div style="font-family: Menlo; font-size: 12px;">
<br /></div>
Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0Toronto, ON, Canada43.653226 -79.38318429999998243.285985999999994 -80.028631299999986 44.020466 -78.737737299999978tag:blogger.com,1999:blog-5673137062674498091.post-6919988084667991372012-12-10T19:20:00.001-05:002016-04-11T14:41:43.032-04:00Running statistics on Oracle tables from Java program.Oracle database query optimizer relies heavily on <a href="http://docs.oracle.com/cd/B19306_01/server.102/b14211/stats.htm">statistics</a>. These statistics are used by the query optimizer to choose the best execution plan for each SQL statement.
Normally, having correct and up-to-date statistics falls under DBA responsibilities (Oracle recommends automatic statistics gathering).
However, there are cases when it might be necessary to update statistics manually, and moreover, at runtime directly from a Java program. For example, when data had been reloaded into the tables and now need to be accessed from a Java batch program while database instance is not configured for automatic statistics update.
Below is an example of Java code that implements a method to gather statistics for a particular table. The code is based on the <a href="http://static.springsource.org/spring/docs/2.5.x/reference/jdbc.html" target="_blank">JdbcDaoSupport</a> class from <a href="http://www.springsource.org/spring-framework" target="_blank">Spring</a> framework but it is a simple convenience and author's preference - there is nothing that would prevent from porting this code to the standard plain JDBC implementation.
<br />
<pre class="java" name="code">/*
* Copyright 2012 VT Enterprise Software Consulting Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.vtesc.examples.db;
import java.sql.Types;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* Demonstrates invocation of <code>dbms_stats.gather_table_stats</code> procedure
* to gather an Oracle table statistics.
* @author Vitali Tchalov
*/
public class JavaOracleStats extends JdbcDaoSupport {
/**
* Updates statistics for <code>table</code> in <code>schema</code> using
* Oracle <code>dbms_stats.gather_table_stats</code> procedure.
*
* @param schema
* @param table
*/
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void gatherTableStats(String schema, String table) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(getJdbcTemplate()
.getDataSource());
jdbcTemplate.setResultsMapCaseInsensitive(true);
SimpleJdbcCall gatherStats = new SimpleJdbcCall(jdbcTemplate)
.withProcedureName("dbms_stats.gather_table_stats")
.withoutProcedureColumnMetaDataAccess()
.useInParameterNames("ownname", "tabname")
.declareParameters(new SqlParameter("ownname", Types.VARCHAR),
new SqlParameter("tabname", Types.VARCHAR));
SqlParameterSource in = new MapSqlParameterSource().addValue("ownname",
schema).addValue("tabname", table);
gatherStats.execute(in);
}
}
</pre>
<br />
This is a fully tested and usable code. But I plan to package this example along with a JUnit test, Spring context file and other artefacts and will publish when ready.
Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com1tag:blogger.com,1999:blog-5673137062674498091.post-60027415735097257272012-09-14T23:58:00.001-04:002012-09-14T23:58:00.203-04:00Frequently used SQL DDL statements<div style="color: #674ea7;"><b><span style="font-size: small;">A collection of reference examples of SQL DDL (Data Definition Language) statements frequently used in application development to create and alter database tables, synonyms, constraints, indexes etc. </span></b><br />
<span style="color: purple; font-size: small;">Note: The statements have been tested on Oracle</span><span style="color: purple; font-size: small;"> 11G database; most probably should work with other relational databases. Some of the datatypes used in the samples are Oracle-specific and would require some tweaking.</span><b><span style="font-size: small;"><br />
</span></b></div><br />
<pre class="brush: sql">-- Create a table
CREATE TABLE TX_HISTORY (
tx_id NUMBER(10, 0) NOT NULL,
stock_id NUMBER(10, 0) NOT NULL,
tx_date DATE NOT NULL,
currency VARCHAR2(5) NOT NULL,
price NUMBER(9, 2) NOT NULL,
price_2 NUMBER
)
/
-- Create a table with a PK (Primary Key) on a single column
CREATE TABLE STOCK (
stock_id NUMBER(10, 0) NOT NULL,
symbol VARCHAR2(5) NOT NULL,
stk_exchange VARCHAR2(5) NOT NULL,
currency VARCHAR2(5) NOT NULL,
--
CONSTRAINT stock_id_pk PRIMARY KEY (stock_id)
)
/
-- Add a PK (Primary Key) to already existing table
ALTER TABLE tx_history ADD CONSTRAINT tx_history_pk PRIMARY KEY (tx_id)
/
-- Create a table with a FK (Foreign Key) to another table
CREATE TABLE STOCK_HISTORY (
rec_id NUMBER(10, 0) NOT NULL,
stock_id NUMBER(10, 0) NOT NULL, -- FK to STOCK table
trade_date DATE NOT NULL,
open_price NUMBER(9, 2) NOT NULL,
close_price NUMBER(9, 2) NOT NULL,
--
CONSTRAINT stock_history_stock_fk FOREIGN KEY (stock_id) REFERENCES stock (stock_id) ENABLE VALIDATE
)
/
-- Add a FK (Foreign Key) to already existing table to reference another table
ALTER TABLE tx_history ADD CONSTRAINT tx_history_stock_fk FOREIGN KEY (stock_id) REFERENCES stock (stock_id) ENABLE VALIDATE
/
-- Drop (delete) a table
DROP TABLE TX_HISTORY
/
-- Add a new column to an existing table
ALTER TABLE TX_HISTORY ADD QTY NUMBER
/
-- Drop a column
ALTER TABLE TX_HISTORY DROP COLUMN PRICE_2
/
</pre><br />
Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0Mimico, Toronto, ON, Canada43.619052348606758 -79.48436774560548243.60730734860676 -79.495182245605477 43.630797348606755 -79.473553245605487tag:blogger.com,1999:blog-5673137062674498091.post-78359627160670678372012-08-15T23:27:00.001-04:002012-08-15T23:27:00.297-04:00NoClassDefFoundError and ClassNotFoundException errors when running standalone Java programs<div style="background-color: #f3f3f3;">This post is intended as a collection of various cases related to Java CLASSPATH issues that cause <b><span style="font-family: "Courier New",Courier,monospace;">NoClassDefFoundError </span></b>and <b style="font-family: "Courier New",Courier,monospace;">ClassNotFoundException </b>errors that are often mysterious and sometimes quite difficult to troubleshoot. </div><div style="background-color: #f3f3f3;">The addressed cases go beyond trivial causes of missing jar files or mistyped package names.</div><br />
<b>Case I - A standalone Java program is packaged into a jar file. The JAR includes a seemingly correct manifest specifying the main class and the program classpath as in the sample below:</b><br />
<br />
MANIFEST.MF file:<br />
<br />
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;"><br />
Manifest-Version: 1.0<br />
Main-Class: com.vtesc.batchjobs.daily.txprocessor.Launcher<br />
Class-Path: . ./txprocessor.jar ./lib/spring.jar ./lib/commons-logging.jar ./lib/ojdbc6.jar <b>d:/common/lib/dbaccess.jar</b><br />
<br />
</div><br />
The txprocessor.jar file is correctly built by an Ant build script and has a totally correct structure and contents:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-oKEuqtlmwfg/UCq-wt0EPPI/AAAAAAAAAB4/KmJz2tEqvSc/s1600/txprocessor-jar-struct.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-oKEuqtlmwfg/UCq-wt0EPPI/AAAAAAAAAB4/KmJz2tEqvSc/s1600/txprocessor-jar-struct.png" /></a></div><div class="separator" style="clear: both; text-align: center;"></div><br />
<br />
Everything seems to be perfectly fine but when run, it fails with classloader errors (Java version "1.6.0_29"):<br />
<br />
<br />
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">D:\batchjobs\txprocessor>java -jar txprocessor.jar<br />
Exception in thread "main" java.lang.NoClassDefFoundError: com/vtesc/batchjobs/daily/txprocessor/Launcher<br />
Caused by: java.lang.ClassNotFoundException: com.vtesc.batchjobs.daily.txprocessor.Launcher<br />
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)<br />
at java.security.AccessController.doPrivileged(Native Method)<br />
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)<br />
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)<br />
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)<br />
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)<br />
Could not find the main class: com.vtesc.batchjobs.daily.txprocessor.Launcher. Program will exit.</div><br />
<b>Cause:</b><br />
The returned error displaying the <span style="background-color: #fff2cc;">"Could not find the main class"</span> message can be actually quite misleading as it may make you to suspect some problem with the main class. However, in this case it has absolutely nothing to do with the main class. The cause of the error is actually in the <span style="color: #660000; font-family: "Courier New",Courier,monospace;">Manifest </span>file on the <span style="color: #660000; font-family: "Courier New",Courier,monospace;">Class-Path:</span> line:<br />
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;"><br />
d:/common/lib/dbaccess.jar<br />
<br />
</div><br />
Hard-coding an absolute path to a library is a very bad practice in itself but specifying the path without indicating a protocol causes the total failure. By default, the Java platform uses the <a href="http://docs.oracle.com/javase/6/docs/api/java/net/URLClassLoader.html" target="_blank">java.net.URLClassLoader</a> class for loading program classes. As its name implies, the <span style="color: #660000; font-family: "Courier New",Courier,monospace;">URLClassLoader </span>uses another system class, <a href="http://docs.oracle.com/javase/6/docs/api/java/net/URL.html" target="_blank">java.net.URL</a> for specifying the resource location. The <span style="color: #660000; font-family: "Courier New",Courier,monospace;">URL </span>class complies with a number of RFC documents and it requires the <b style="font-family: "Courier New",Courier,monospace;"><span style="color: #660000;">file:/</span></b> protocol to be specified for file system resources.<br />
<br />
The problem can be corrected by prefixing the absolute path to the dbaccess.jar file with the file:/ protocol as shown below:<br />
<br />
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;"><br />
Manifest-Version: 1.0<br />
Main-Class: com.vtesc.batchjobs.daily.txprocessor.Launcher<br />
Class-Path: . ./txprocessor.jar ./lib/spring.jar ./lib/commons-logging.jar ./lib/ojdbc6.jar <b>file:/d:/common/lib/dbaccess.jar</b><br />
<br />
</div><br />
Yet, a better way would be not to use absolute paths. Case in point, using the Windows specific path here will confine this Java program to the Windows platform which goes against the Java platform-independence principle.<br />
But we live in a world which is far from perfect and sometimes one finds himself forced to follow requirements even if they go against best practices and common sense.<br />
<br />
Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0tag:blogger.com,1999:blog-5673137062674498091.post-46469418504191525412012-08-09T22:43:00.002-04:002012-12-06T13:09:25.464-05:00Samples of control files for Oracle SQL LoaderThis is intended as a quick reference to provide a set of templates for creating SQL Loader control files for most frequently used scenarios. <br />
<br />
<b>Sample 1:</b><br />
Loading data from a TAB-delimited file: FIELDS TERMINATED BY X'09'<br />
The sample also demonstrates the following techniques:<br />
<ul>
<li>skip lines: OPTIONS (SKIP=1) instructs the SQL Loader to skip the first line (the number specifies the number of lines)</li>
<li>auto-generate values for a primary key column: SEQUENCE(MAX, 1) </li>
<li>load data by adding more rows without truncating the existing data: APPEND</li>
<li>load into DATE type columns: "TO_DATE(:TX_DATE,'MM/DD/YYYY')" </li>
</ul>
<br />
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">
-- ============================================================<br />
-- stocktx.ctl </div>
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">
-- SQLLDR Control File for data loading to STOCKTX table.<br />
--<br />
-- The input file has the TAB-separated format with a single line per table row.<br />
--<br />
-- To run (sample): <br />
-- sqlldr batchjob/<pwd>@oradb control=stocktx.ctl errors=1000 log=logs/stocktx_load.log<br />
<br />
OPTIONS (SKIP=1)
load data<br />
infile 'data/stocktx_data.tab'<br />
badfile 'logs/stocktx_data.bad'<br />
discardfile 'logs/stocktx_data.discard'<br />
APPEND<br />
into table portfolio.stocktx<br />
FIELDS TERMINATED BY X'09'<br />
trailing nullcols<br />
(<br />
TX_ID SEQUENCE(MAX, 1),<br />
EXCHANGE,<br />
SYMBOL,<br />
QTY,<br />
PRICE,</div>
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">
TX_DATE "TO_DATE(:TX_DATE,'MM/DD/YYYY')"</div>
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">
)</div>
<br />
<b>Sample 2:</b><br />
Loading data from a multicharacter-delimited file (^|^) file: FIELDS TERMINATED BY '^|^'<br />
The sample also demonstrates the following techniques:<br />
<ul>
<li>delete existing data prior to the load: TRUNCATE</li>
<li>specify the data file name on the command line: data=addr.dsv</li>
<li>specify log files pathnames via command line parameters (as opposite to hard-coding in the control file).</li>
<li>evaluate the source values and transform on a condition, e.g if the Postal Code is "N/A", replace it with NULL: ZIP_CODE "decode(:ZIP_CODE, 'N/A', '', :ZIP_CODE)"</li>
</ul>
<ul>
<li>apply the current time/date to a DATE column: SYSDATE </li>
</ul>
<ul>
<li>CONSTANT - allows to set a column to a constant value; this value is hard-coded into the control script file, not from the input data file. The value is treated as a character string; SQLLDR will attempt to convert it to the column type if required.</li>
</ul>
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">
-- ============================================================<br />
-- addr.ctl<br />
-- SQLLDR Control File for data loading to ADDR table.<br />
--<br />
-- The input file the '^|^' sequence of characters to separate values.<br />
--<br />
-- To run (sample):<br />
-- sqlldr batchjob/<pwd>@oradb control=addr.ctl errors=100 log=logs/addr_load.log bad=logs/addr.bad discard=logs/addr.discard data=addr.dsv<br />
-- <br />
-- Note: the logs directory needs to be created prior to running the script.<br />
<br />
OPTIONS (SKIP=0)
<br />
<br />
load data<br />
TRUNCATE<br />
into table ADDR<br />
FIELDS TERMINATED BY '^|^'<br />
trailing nullcols<br />
(<br />
ADDR_ID SEQUENCE(MAX, 1),<br />
CITY,<br />
STREET_NUM,<br />
STREET_NAME,<br />
STREET_DIR,<br />
ZIP_CODE "decode(:ZIP_CODE, 'N/A', '', :ZIP_CODE)",<br />
MODIFIED_ON SYSDATE,</pwd><br />
<pwd> BATCH_ID CONSTANT 1<br />
)
<br />
</pwd></div>
<br />
This is a table structure for the sample above:
<br />
<pre class="brush: sql">CREATE TABLE ADDR (
addr_id NUMBER(10) NOT NULL,
city VARCHAR2(40) NOT NULL,
street_num NUMBER NOT NULL,
street_name VARCHAR2(40) NOT NULL,
street_dir VARCHAR2(4) NOT NULL,
zip_code VARCHAR2(7),
modified_on DATE NOT NULL,
batch_id NUMBER,
--
CONSTRAINT addr_id_pk PRIMARY KEY (addr_id)
)
/</pre>
<b>Sample 3:</b><br />
SQLLDR control file to load data from a comma-separated file (,) where field values may be enclosed in double-quotes (").<br />
<br />
<br />
Control file explanation:<br />
<ul>
<li>FIELDS TERMINATED BY ',' - specifies that the fields are delimited by comma.</li>
<li>OPTIONALLY ENCLOSED BY '"' - specifies that field values may (or may not) be enclosed in double quotes, for example: "2269 Lake Shore Blvd. W., Toronto, ON"<br />This is often required if the data can contain characters that are used for field separation, the comma character in this particular example.</li>
<li>SEQUENCE(COUNT, 1) - this is usually used to generate unique values for the table primary key. The COUNT parameter specifies that the 1st value to be the number of records in the table before the load plus 1.</li>
<li>-- INTO TABLE ADDR.STREET_VALUES_BAK - a commented out line; it is handy during the development phase when the control file can be re-used to load data into different tables.</li>
<li> "UPPER(:ALT_STREET_NAME)" - convert the values to the upper case.</li>
<li>CREATE_DATE "TO_DATE(TO_CHAR(SYSDATE, 'YYYYMMDD'), 'YYYYMMDD')" - this is useful to load only the date part of the current time into DATE type columns. <br />SYSDATE returns the current time which is formatted into a string containing Year, Month, and Day which in turn converted back to DATE type.</li>
<li>BATCH_ID EXPRESSION "(SELECT MAX(BATCH_ID) FROM ADDR.BATCH_ID WHERE TABLE_NAME = 'STREET_ALTERNATIVE')" - useful to insert a constant value for each data load, for a example a Batch ID or Run ID. <br />A separate table is required, of course, to maintain load data IDs. A new record can be inserted into this table from a shell script prior to invoking the SQLLDR script. See a DDL and INSERT statement below.</li>
</ul>
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">
-- =============================================================<br />
-- street_alternative.ctl<br />
-- Loading alternative street names.<br />
-- SQLLDR Control File for data loading into ADDR.STREETS_ALTERNATIVE table.<br />
--<br />
-- The input file is |-separated in double quotes.<br />
-- sqlldr vit1@devdb1 control=street_alternative.ctl errors=1 log=logs/street_alternative.log bad=logs/street_alternative.bad discard=logs/street_alternative.discard data=street_alternative.txt<br />
--<br />
<br />
OPTIONS (SKIP=1)<br />
<br />
LOAD DATA<br />
APPEND <br />
INTO TABLE ADDR.STREET_ALTERNATIVE<br />
-- INTO TABLE ADDR.STREET_VALUES_BAK<br />
FIELDS TERMINATED BY ','<br />
OPTIONALLY ENCLOSED BY '"'<br />
TRAILING NULLCOLS ( <br />
REC_ID SEQUENCE(COUNT, 1),<br />
STREET_ID, <br />
ALT_STREET_NAME "UPPER(:ALT_STREET_NAME)", <br />
CREATE_DATE "TO_DATE(TO_CHAR(SYSDATE, 'YYYYMMDD'), 'YYYYMMDD')",<br />
BATCH_ID EXPRESSION "(SELECT MAX(BATCH_ID) FROM ADDR.BATCH_ID WHERE TABLE_NAME = 'STREET_ALTERNATIVE')"<br />
)<br />
<br />
<br /></div>
<br />
DDL for the tables used in the sample #3 above:
<br />
<pre class="brush: sql">
CREATE TABLE ADDR.STREET_ALTERNATIVE (
rec_id NUMBER NOT NULL,
street_id NUMBER NOT NULL,
alt_street_name VARCHAR2(40) NOT NULL,
create_date DATE NOT NULL,
batch_id NUMBER NOT NULL,
--
CONSTRAINT rec_id_pk PRIMARY KEY (rec_id)
)
/
</pre>
<pre class="brush: sql">CREATE TABLE ADDR.BATCH_ID (
rec_id NUMBER NOT NULL,
table_name VARCHAR2(255) NOT NULL,
batch_id NUMBER NOT NULL,
create_date DATE NOT NULL,
--
CONSTRAINT batch_id_pk PRIMARY KEY (rec_id)
)
/
</pre>
<pre class="brush: sql">
-- A statement to insert a record into the BATCH_ID table for
-- the next value to be used in a data load:
insert into ADDR.BATCH_ID values (1, 'STREET_ALTERNATIVE',
(select nvl(max(batch_id), 0) from ADDR.BATCH_ID
where table_name = 'STREET_ALTERNATIVE') + 1, sysdate)
/
</pre>
Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com11tag:blogger.com,1999:blog-5673137062674498091.post-79059800811982627822012-07-05T21:12:00.001-04:002012-07-05T21:12:00.187-04:00Oracle Database Management for Application Developers<h2>A set of how-to's and tips for managing an Oracle 10g/11g database targeted for non-DBA folks such as Application Architects and Java Developers.</h2><br />
<h4>Problem: The Enterprise Management (EM) webapp console can no longer be started after a password change.</h4>This tip is specific to running Oracle on Windows. Normally the installer will register a Windows service for the EM console. Assuming the default settings for the instance and host were kept, the service name is likely to be <b><span style="font-family: "Courier New",Courier,monospace;">OracleDBConsoleorcl</span></b>.<br />
Since it is a full-blown web application running under OC4J application server, it's quite heavy on the hardware; so, as a post-installation step it is common to change the service default Startup Type from Automatic to Manual and launch it only when there is a need.<br />
If all of a sudden the service begins to fail to start, chances are that the message and error code reported by the service will be very generic and most likely useless for troubleshooting.<br />
So, the first thing to do is to locate the EM deployment directory which contains log files. Normally (the tip assumes an installation on a single host, not cluster), it will be under the <DBHOME> directory; for example, a typical location:<br />
<div style="font-family: "Courier New",Courier,monospace;">....\product\11.2.0\dbhome_1\localhost_orcl\sysman\log</div><br />
One possible reason could be the expired password for the <b><span style="font-family: "Courier New",Courier,monospace;">SYSMAN </span></b>user. The SYSMAN is the default super user account created by the installer to set up and administer the Enterprise Manager. It is also the database account that owns the objects stored in the Oracle Management Repository.<br />
<br />
Seeing the following exceptions in the <b style="font-family: "Courier New",Courier,monospace;">emoms.log</b> file is a good indication that something is wrong with the SYSMAN account:<br />
<div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">Caused by: java.sql.SQLException: ORA-01017: invalid username/password; logon denied<br />
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:73)<br />
... </div><div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">java.sql.SQLException: ORA-28000: the account is locked<br />
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:73)</div><div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;"> </div><br />
In one particular case (that inspired this post), it was a forced password change after logging in to EM. The passwords had expired for a number of system accounts, SYSMAN included, and I was forced to change them. The submitted request led the EM console app to crash and it was impossible to start it again. <i>(In retrospect, a better course of action probably was to shutdown the EM and </i><i>instead </i><i>change the passwords from sqlplus but it's a topic for a different post)</i>.<br />
This is what helped to resolve the situation:<br />
<ul><li>Locate the <span style="background-color: #fff2cc; color: black; font-family: "Courier New",Courier,monospace;">emoms.properties</span> file for the EM. It should be at a path similar to this: <span style="font-family: "Courier New",Courier,monospace;">C:\app\<user_account>\product\11.2.0\dbhome_1\localhost_orcl\sysman\config</span></li>
<li style="font-family: inherit;">Make a backup copy of the file and then edit these 2 properties: <br />
<span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">oracle.sysman.eml.mntr.emdRepPwd=<new_password></span><br style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;" /><span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">oracle.sysman.eml.mntr.emdRepPwdEncrypted=FALSE</span></li>
<li style="font-family: inherit;">Use <span style="font-family: "Courier New",Courier,monospace;">sqlplus</span> command line tool or any other client to connect with a system account (e.g. SYS) and run the following statement to change the password and unlock the SYSMAN account:<br />
<span style="background-color: #fff2cc; font-family: Courier New;">alter user SYSMAN identified by <new_password> account unlock;</span></li>
<li style="font-family: inherit;">Shutdown the database server service (usually named <span style="font-family: "Courier New",Courier,monospace;">OracleServiceORCL</span>), the listener (<span style="font-family: "Courier New",Courier,monospace;">OracleOraDb11g_home1TNSListener</span>) and whatever other related Oracle services (<span style="font-family: "Courier New",Courier,monospace;">OracleJobSchedulerORCL</span>, <span style="font-family: "Courier New",Courier,monospace;">OracleMTSRecoveryService</span>, etc.) and for a good measure reboot the Windows. </li>
<li style="font-family: inherit;">Start back the <span style="font-family: "Courier New",Courier,monospace;">OracleServiceORCL</span> and <span style="font-family: "Courier New",Courier,monospace;">OracleOraDb11g_home1TNSListener</span> services. After that, the EM service, <span style="font-family: "Courier New",Courier,monospace;">OracleDBConsoleorcl</span>, should start successfully. <br />
Keep in mind that the password used for the SYSMAN account is not necessarily the same used to login into EM; normally you login to EM with the SYS account as SYSDBA and have to use the password set for the SYS user. The SYSMAN account is a system account not to be used by human users. </li>
</ul>Check the <span style="background-color: #fff2cc; color: black; font-family: "Courier New",Courier,monospace;">emoms.properties</span> configuration file - the previously edited <span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">emdRepPwd</span> property should be now overridden with an encrypted value for the password and the <span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">emdRepPwdEncrypted</span> should be reset back to TRUE by the EM.<br />
In case this tip has not helped to resolve the problem, check again the log files, particularly <span style="font-family: "Courier New",Courier,monospace;">OracleDBConsoleorclsrvc.log</span>, <span style="font-family: "Courier New",Courier,monospace;">emdb.nohup</span> and <span style="font-family: "Courier New",Courier,monospace;">emoms.log</span>, for clues.<br />
Also, a message log at C:\app\<user_account>\diag\rdbms\orcl\orcl\alert\log.xml contains alerts that reference errors and detailed log files.<br />
And finally, refer to <a href="http://docs.oracle.com/html/B12013_03/repository.htm" target="_blank">Maintaining and Troubleshooting the Repository</a> in Oracle Enterprise Manager Advanced Configuration 10g documentation for help.<br />
<br />
Check out the following tip to disable the password expiry to prevent these kind of troubles in the future.<br />
<br />
<h4>Tip: Change password expiration policy</h4>For a locally installed developer instance of Oracle database, the security is often of no concern. On the contrary, it can be quite a hussle when the database is used only by a single developer or a small team.<br />
It therefore makes sense to disable password expiry for system accounts to prevent troubles such as one described above. Normally, most of the system accounts are locked by default in simple installations such as a development instance, but SYS, SYSTEM, SYSMAN, MGMT_VIEW have to be unlocked and active even in a minimal configuration.<br />
In Oracle, the password expiry policy is defined on the profile level.<br />
By default, the Oracle installer creates these system accounts under the DEFAULT profile. If these assumptions are applicable, then executing the statement below will disable password expiration:<br />
<div style="background-color: #fff2cc;"><br />
</div><div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">ALTER PROFILE "DEFAULT" LIMIT PASSWORD_LIFE_TIME UNLIMITED;</div><div style="background-color: #fff2cc;"><br />
</div>Of course, this will impact every user account (a.k.a. schema) that is based on the DEFAULT profile.<br />
<br />
The same can be achieved via the EM - log in under SYS user as SYSDBA and navigate to the Sever > Profiles > DEFAULT page. Click Edit and then select the Password tab. In the Password section put UNLIMITED (or click on the lookup icon) into the "<span class="x8">Expire in (days)" input field.</span>Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0tag:blogger.com,1999:blog-5673137062674498091.post-62727703801980475292011-03-26T23:12:00.000-04:002011-03-26T23:12:30.640-04:00<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: large;"><b>Using Sun JSSE on IBM J9 JVM</b></span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><br />
</div><div style="color: #741b47; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: large;"><span style="font-size: small;">A client asked to secure communications between quite old devices running IBM J9 JVM version 1.3. The geographically dispersed devices communicate with central servers via web services over HTTP protocol to sync data. What appeared to be a very simple task to switch to SSL protocol by replacing <span style="font-family: "Courier New",Courier,monospace;">http</span> with <span style="font-family: "Courier New",Courier,monospace;">https</span> in a config file, turned out to be quite a daunting exercise.</span></span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: large;"><span style="color: #741b47; font-size: small;">Though it is unlikely someone else encounters similar tasks, information below may also be helpful for learning intricacies around SSL certificates, keystores and even JSSE in general. </span><b><br />
</b></span></div><br />
<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">In order for an application running on a J2ME device under IBM J9 virtual machine to access a web service provided over secure HTTPS protocol, the procedure described in the document should be implemented.</span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">Prior to JDK 1.4 version, the Java Secure Socket specification was not a part of standard JDK and therefore vendors were not required to implement it. It is quite likely that IBM did implement SSL in their J9 JVM version 1.3, however, it had not been possible to locate any usable user and developer documentation. On the contrary, Sun provided a well-documented reference implementation called <a href="http://java.sun.com/products/archive/jsse/">JSSE</a>. This document describes how to setup and configure the Sun JSSE library on a device running IBM J9 Java virtual machine.</span></div><span style="color: #20124d; font-family: inherit; font-size: small;"><span style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">The JSSE setup would be a straightforward exercise except that there is a problem with the keystore format. The JDK 1.3 specification, particularly </span><span style="color: black; font-family: "Courier New",Courier,monospace;">java.securtiy.KeyStore</span> <span style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">class, does not specify persistence mechanism to store keys and certificates. Apparently, the JSSE library relies on a vendor implementation, in this case IBM, for providing persistence mechanism. Attempting to connect over HTTPS protocol using the standard</span> <span style="font-family: "Courier New",Courier,monospace;"><span style="color: black;">cacerts</span> </span><span style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">keystore file results in the</span></span><span style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"> </span><span style="color: black; font-family: "Courier New",Courier,monospace;">“java.net.SocketException: SSL implementation not available”</span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"> exception. This is, however, not the root cause of the problem. As it turned out, the JSSE fails to initialize the truststore providing this error message: </span><br />
<div style="color: black; font-family: "Courier New",Courier,monospace;">“default context init failed: java.security.PrivilegedActionException: java.io.IOException: Invalid keystore”</div><div style="font-family: "Courier New",Courier,monospace;"><br />
</div><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">Running J9 with the </span><span style="color: black; font-family: "Courier New",Courier,monospace;">–verbose</span> <span style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="color: #20124d;">flag reveals that JVM loads</span> </span><span style="color: black; font-family: "Courier New",Courier,monospace;">com/ibm/oti/security/provider/KeyStore</span> <span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">class. In the contrast, the same test code, run under Sun JRE 1.3_15, loads the </span><span style="font-family: "Courier New",Courier,monospace;"><span style="color: black;">sun.security.provider.JavaKeyStore</span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="color: black;"> </span>class from the</span> <span style="color: black;">rt.jar</span></span>. <span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">Therefore, the conclusion is that IBM persistence implementation of </span><span style="color: black; font-family: "Courier New",Courier,monospace;">keystore </span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">is not compatible with the Sun's. This document includes a description of how to convert the standard Sun </span><span style="color: black; font-family: "Courier New",Courier,monospace;">cacerts </span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">file to the IBM J9 specific format that can be processed by the </span><span style="color: black; font-family: "Courier New",Courier,monospace;">com.ibm.oti.security.provider.KeyStore</span><span style="color: black;"> </span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">class.</span><br />
<span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">The </span><b style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">keytool</b><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"> (included in both Sun and IBM JVM distributions) utility stores the keys and certificates in a so-called </span><b><i style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">keystore</i></b><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">.</span> <span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">By default, both Sun and IBM implement the keystore as a file in JKS format. However, the IBM file format is not compatible with Sun JKS format. The following is the description on how to create a keystore file in IBM J9 format and install and configure Sun JSSE library to run in J9 VM. </span><br />
<br />
<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; margin-left: 18pt;"><span style="font-size: small;"><b>1. </b><b>Export the root Certification Authority certificates from the standard <span style="font-family: "Courier New",Courier,monospace;">cacerts </span>file.</b></span></div><div style="margin-left: 39.6pt;"><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">1.1.</span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"> Open a console window and navigate to a working directory, e.g. </span><span style="color: black; font-family: Verdana; font-size: small;">c:\projects\certificates</span></div><div style="margin-left: 39.6pt;"><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; font-size: small;">1.2.</span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"> Set path to </span>Sun’s keytool with the command, for example in Windows:</span><br />
<div style="color: black; font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">set PATH=<JDK-installation>/jre/bin;%PATH%</span></div></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; margin-left: 39.6pt;">1.3. Locate the <b>cacerts</b> file in <span style="color: black; font-family: "Courier New",Courier,monospace;">jre\lib\security</span> folder of a Sun JDK installation and copy it into the working directory. </div><div style="margin-left: 39.6pt;"><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">1.4. List all available certificates with the command into a temporary file:</div><div style="color: black; font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">keytool -list -keystore cacerts > temp.txt</span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">When prompted, enter the password ‘<b>changeit</b>’ (it is a default password that was set by Sun). Here is a sample what the file should contain:</div><blockquote style="background-color: #fff2cc;"><span style="color: black; font-family: "Courier New",Courier,monospace;">Enter keystore password:changeit</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;">Keystore type: jks</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;">Keystore provider: SUN</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;">Your keystore contains 33 entries:</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;"><b>verisignclass1g3ca</b>, Thu Mar 25 14:27:59 EST 2004, trustedCertEntry, Certificate fingerprint (MD5): B1:47:BC:18:57:D1:18:A0:78:2D:EC:71:E8:2A:95:73</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;"><b>equifaxsecureebusinessca1</b>, Fri Jul 18 14:43:22 EDT 2003, trustedCertEntry, Certificate fingerprint (MD5): 64:9C:EF:2E:44:FC:C6:8F:52:07:D0:51:73:8F:CB:3D</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;"><b>verisignclass2g2ca</b>, Thu Mar 25 14:18:49 EST 2004, trustedCertEntry, Certificate fingerprint (MD5): 2D:BB:E5:25:D3:D1:65:82:3A:B7:0E:FA:E6:EB:E2:E1</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;"><b>verisignclass3g3ca</b>, Thu Mar 25 14:31:09 EST 2004, trustedCertEntry,</span><br />
<span style="color: black; font-family: "Courier New",Courier,monospace;">...</span></blockquote><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><br />
1.5. Each certificate in <b>cacerts</b> file has to be exported into an individual certificate file. To do this, you need to run the following command for each alias (aliases are shown in bold in the sample above. If you want, you can edit the file to leave only aliases in it – this is all information that you need from this temporary file):</div></div><div style="margin-left: 39.6pt;"><blockquote style="background-color: #fff2cc; color: black; font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">keytool -export -keystore cacerts -file <alias>.cer -alias <alias></span></blockquote><span style="font-family: Verdana; font-size: small;"><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">where <span style="color: black; font-family: "Courier New",Courier,monospace;"><alias></span> is an alias in the file, e.g. </span><span style="color: black; font-family: "Courier New",Courier,monospace;">verisignclass1g3ca</span></span><span style="font-size: small;">. <span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">On each run you will have to enter the password – ‘changeit’.</span></span><br />
</div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; margin-left: 18pt;"><b>2.</b><b> Import the root certificates into IBM-specific file.</b><br />
For this procedure you need an IBM keytool utility that generates keystore file in J9 1.3 specific format. One place where it can be found is a WebSphere Studio Device Developer package. </div><div style="margin-left: 39.6pt;"><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">2.1. There are several keytool utilities in the package. To find the right one you can try this: search the WSDD installation directory for <span style="color: black; font-family: "Courier New",Courier,monospace;">keytool.exe</span> files. Open a console window and navigate to the directory that contains a <span style="color: black; font-family: "Courier New",Courier,monospace;">keytool.exe</span>. Because the file formats are incompatible, the IBM keytool is not able to understand the Sun format (and vice versa). To test it, try to list certificates from the Sun keystore file by running the command: </div><div style="background-color: #fff2cc; color: black; font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">keytool –list –keystore c:\projectes\certificates\cacert</span></div><br />
<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">At the prompt, enter the password </span><span style="font-size: small;"><span style="color: black; font-family: "Courier New",Courier,monospace;"></span></span><span style="color: black; font-family: "Courier New",Courier,monospace; font-size: small;">changeit</span><span style="font-size: small;"><span style="color: black; font-family: "Courier New",Courier,monospace;"></span></span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">If it fails with a message similar to this: </span><span style="font-size: small;"><span style="color: black; font-family: "Courier New",Courier,monospace;">keytool error: java.io.IOException: Invalid keystore</span>, this is the utility that you need.</span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">In the default installation of a trial version of WSDD 5.6, the keytool utility is located in the following directory:</span></div><div style="color: black; font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">C:\Program Files\IBM\DeviceDeveloper5.6\wsdd5.0\ive-2.1\bin </span></div><br />
<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">When running the IBM keytool utility, make sure that the environment does not have <span style="color: black; font-family: "Courier New",Courier,monospace;">JAVA_HOME</span> variable, otherwise the utility will not be able to locate the runtime library and will fail with a message similar to this:</span></div><blockquote style="background-color: #fff2cc;"><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><span style="color: black; font-family: "Courier New",Courier,monospace;">Fatal error: Unable to find and initialize required class java/lang/Object</span></span></div></blockquote></div><div style="margin-left: 39.6pt;"><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">2.2. Import each certificate file that was created in the step 1 to an IBM-specific keystore by running the following command:</span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><br />
</div><div style="background-color: #fff2cc; color: black; font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">keytool -import -alias <alias> -file c:\projects\certificates\<alias>.cer -keystore c:\projects\certificates\cacerts.j9 </span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><br />
</div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">Enter the same password for each certificate.<br />
</div></div><div style="margin-left: 18pt;"><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><b>3. </b><b>HTTPS Support </b></span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">The JSSE implementation contains a URL handler for the HTTPS protocol. In order to use this handler, the handler's implementation package name has to be added to the list of packages which are searched by the java URL class. This is configured via the <span style="color: black; font-family: "Courier New",Courier,monospace;">"java.protocol.handler.pkgs"</span> system property. See the <span style="color: black; font-family: "Courier New",Courier,monospace;">java.net.URL</span> class documentation for details.</span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">System properties can be set via the command line or at runtime through the <span style="color: black; font-family: "Courier New",Courier,monospace; font-size: small;">java.lang.System</span> class.</div></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; margin-left: 18.7pt;">For example, you can set this property on the command line via:<br />
<br />
<span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">java -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol</span><br />
<br />
When<span style="font-size: small;"><span style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"> accessing HTTPS servers through a web proxy, you must set the </span><span style="font-family: "Courier New",Courier,monospace;"> "https.proxyHost"</span> <span style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">and </span><span style="color: black; font-family: "Courier New",Courier,monospace;">"https.proxyPort" </span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">system properties to the correct host name and port number of the web proxy. For example, to set this property on the command line to access HTTPS servers through the proxy host "webproxy" running at port 8080 you would use:</span></span></div><div style="margin-left: 18.7pt;"><span style="font-family: Verdana; font-size: small;"><span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">java -Dhttps.proxyHost=webproxy -Dhttps.proxyPort=8080</span><br />
</span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; font-size: small;">To configure the handler at runtime, the following code has to be added to the application start-up module:</span></div><blockquote><span style="font-family: Verdana; font-size: small;"><span style="background-color: #fff2cc; color: black; font-family: "Courier New",Courier,monospace;">System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");</span><br />
</span></blockquote><div style="margin-left: 18pt;"><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><b>4.</b><b> Configuring the TrustManager keystore location.</b> </span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">The created in the step 2 <span style="color: black; font-family: "Courier New",Courier,monospace;">cacerts.j9</span> file is a keystore file in an IBM J9 specific format. This file has to be available to the JVM running a program that uses SSL. The location of the file and the password for the keystore can be specified through appropriate system properties dynamically, e.g. </span></div><div style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">java -Djavax.net.ssl.trustStore=cacerts.j9 -Djavax.net.ssl.trustStorePassword=<password></span></div></div><div style="margin-left: 18pt;"><span style="font-size: small;"><br />
</span><br />
<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">or they can be statically coded into a program like this:</span></div></div><div style="margin-left: 18pt; text-indent: 18pt;"><span style="font-family: Verdana; font-size: small;"><br />
</span><br />
<blockquote><span style="font-family: Verdana; font-size: small;"> <span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace;">System.setProperty("javax.net.ssl.trustStore", "cacerts.j9");</span></span></blockquote></div><div style="margin-left: 18pt; text-indent: 18pt;"><blockquote style="background-color: #fff2cc;"><div style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">System.setProperty("javax.net.ssl.trustStorePassword", “<password>”);</span></div></blockquote></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; margin-left: 18pt;"><span style="font-size: small;"><b>5. </b><b>Sun Java Secure Socket Extension package</b></span><br />
<span style="font-size: small;">Download Sun Java Secure Socket Extension package – JSSE from <a href="http://java.sun.com/products/jsse/index.jsp" rel="nofollow">http://java.sun.com/products/jsse/index.jsp</a></span><br />
<span style="font-size: small;">The JSSE version 1.0.3_03 is the latest (and the last) implementation available for Java 1.2 and 1.3 (Update: it has reached EOL now). Install the package on a development computer. You can find 3 jar files in the JSSE lib directory: <span style="font-family: "Courier New",Courier,monospace;">jcert.jar, jnet.jar, jsse.jar</span>. Copy the files to a lib directory on a clock device and include them into the classpath.</span><br />
</div><div style="margin-left: 18pt;"><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; font-size: small;"><b>6.</b><b> Register the SunJSSE provider.</b></span><br />
<span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; font-size: small;">To dynamically register the provider, include the following line into the application startup code:<b><br />
</b></span><span style="background-color: #fff2cc; font-family: Verdana; font-size: small;">Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());</span><span style="background-color: #fff2cc; font-family: "Courier New",Courier,monospace; font-size: small;"> </span><br />
<br />
<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;">Detailed instructions can be found in INSTALL.txt file of the JSSE installation.</span></div></div><div style="margin-left: 18pt;"><br />
<div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><b>7. </b><b>To test the installation</b> </span></div><span style="font-size: small;"><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">Configure the device to access a server via HTTPS protocol. If the server uses a certificate signed by a Certificate Authority (CA), verify that the CA was added to the </span></span><span style="font-size: small;"><span style="color: black; font-family: "Courier New",Courier,monospace;">cacerts.j9</span> </span><span style="font-size: small;"><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"> file (Step 2). If using a self-signed certificate, add the certificate to the </span><span style="color: black; font-family: "Courier New",Courier,monospace;">cacerts.j9</span> <span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">following the procedure described in step 2. </span></span><br />
<span style="font-size: small;"><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;">Copy the </span><span style="color: black; font-family: "Courier New",Courier,monospace;">cacerts.j9</span><span style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"> file to a device. Run the device application launching it from a starter class that adds the security provider (step 6). Verify log files contain no errors when accessing the web services over HTTPS.</span></span><br />
<div style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><br />
</div></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><b>Useful links that can be used for understanding the subject and troubleshooting:</b></span></div><div style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><a href="http://www.informit.com/articles/article.asp?p=24604&rl=1" rel="nofollow">http://www.informit.com/articles/article.asp?p=24604&rl=1</a></span></div><div style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/HowToImplAProvider.html" rel="nofollow">http://java.sun.com/j2se/1.4.2/docs/guide/security/HowToImplAProvider.html</a></span></div><div style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><a href="http://java.sun.com/products/jsse/index-103.html" rel="nofollow">http://java.sun.com/products/jsse/index-103.html</a></span></div><div style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><a href="http://www-106.ibm.com/developerworks/java/library/j-customssl/" rel="nofollow">http://www-106.ibm.com/developerworks/java/library/j-customssl/</a></span></div><div style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><a href="http://www-1.ibm.com/support/docview.wss?uid=swg21179602" rel="nofollow">http://www-1.ibm.com/support/docview.wss?uid=swg21179602</a></span></div><div style="font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><span style="font-size: small;"><a href="http://www-1.ibm.com/support/docview.wss?rs=840&context=SSSUDG&dc=DB520&uid=swg21195526&loc=en_US&cs=utf-8&lang=en" rel="nofollow">http://www-1.ibm.com/support/docview.wss?rs=840&context=SSSUDG&dc=DB520&uid=swg21195526&loc=en_US&cs=utf-8&lang=en</a></span></div><div style="color: #20124d; font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;"><br />
</div>Vitali Tchalovhttp://www.blogger.com/profile/10030227566242734336noreply@blogger.com0