tag:blogger.com,1999:blog-70826844021406570042024-03-13T21:26:13.354-07:00Blog on ProgrammingThis is a collection of notes on programming by Mykola Dzyuba.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.comBlogger18125tag:blogger.com,1999:blog-7082684402140657004.post-64349224520859376942015-08-29T00:24:00.001-07:002015-08-29T00:26:21.570-07:00Creating a HelloWorld Android App for Amazon Fire PhoneI've tried creating a sample project for Amazon Fire Phone and found a few issues and workarounds. I thought it might be helpful to share them here. It might be useful to Android developers getting started with Amazon Fire Phone programming.<br />
<br />
I've followed steps on <a href="https://developer.amazon.com/public/resources/development-tools/ide-tools/tech-docs/01-setting-up-your-development-environment">setting up development environment</a> provided by the Amazon site. Once I've got an Amazon Fire Phone SDK Addon installed, I've created a sample app in Android Studio v1.3.2. In this example, I am using buildToolsVersion "23.0.0"<br />
<br />
Here are the steps for creating a new project:<br />
<br />
Android Studio v1.3.2.<br />
- File > New > New Project<br />
- Application Name: HelloWorld<br />
- Company Domain: practice.mdzyuba.com<br />
- Next<br />
- Check on Phone and Tablet box<br />
- Select Minimum SDK: API 17: Android 4.2 (Jelly Bean)<br />
- Next<br />
- Select a Blank Activity to be added<br />
- Next<br />
- Finish<br />
<br />
The projects has failed to compile and I've got a few errors:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">/Users/mykola/Code/practice/android_practice/amazon/HelloWorld/app/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.0/res/values-v23/values-v23.xml</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(2) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Inverse'.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(2) Error retrieving parent for item: No resource found that matches the given name 'android:Widget.Material.Button.Colored'.</span><br />
<br />
It looks like an Android Studio issue <a href="https://code.google.com/p/android/issues/detail?id=183478">https://code.google.com/p/android/issues/detail?id=183478</a>.<br />
<br />
A workaround is to change or comment out the <span style="font-family: Courier New, Courier, monospace; font-size: x-small;">com.android.support:appcompat </span>dependency in build.gradle:<br />
<br />
app/build.gradle:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">apply plugin: 'com.android.application'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">android {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> compileSdkVersion 22</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> buildToolsVersion "23.0.0"</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> defaultConfig {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> applicationId "com.mdzyuba.practice.sample1"</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> minSdkVersion 17</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> targetSdkVersion 17</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> versionCode 1</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> versionName "1.0"</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> buildTypes {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> release {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> minifyEnabled false</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">dependencies {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> compile fileTree(include: ['*.jar'], dir: 'libs')</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// compile 'com.android.support:appcompat-v7:23.0.0'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> compile "com.android.support:appcompat-v7:22.+"</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
<div>
After that, the project build is successful.</div>
<div>
<br /></div>
<div>
Next, I change the gradle version as suggested by the Amazon instructions:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">build.gradle:</span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> dependencies {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// classpath 'com.android.tools.build:gradle:1.3.0'</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> classpath 'com.amazon.device.tools.build:gradle:1.1.+'</span></div>
</div>
<div>
<br /></div>
<div>
Now, I've got an error: </div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:Gradle 2.4 requires Android Gradle plugin 1.2.0 (or newer) but project is using version 1.1.3.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Please use Android Gradle plugin 1.2.0 or newer.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Fix plugin version and sync project</span></div>
</div>
<div>
<br /></div>
<div>
I've modified Project Structure > Project > Gradle version: 2.2.1. I've got this version from the Amazon examples. After that, I've got a few more errors</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">.../Sample1/app/build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.2.1/res/values-v21/values-v21.xml</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(2) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material'.</span></div>
</div>
<div>
<br /></div>
<div>
So, I've decided to comment out <span style="font-family: Courier New, Courier, monospace; font-size: x-small;">com.android.support:appcompat</span> dependency completely:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">app/build.gradle:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">dependencies {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> compile fileTree(include: ['*.jar'], dir: 'libs')</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// compile 'com.android.support:appcompat-v7:23.0.0'</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// compile "com.android.support:appcompat-v7:22.+"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span></div>
</div>
<div>
<br /></div>
<div>
Now, I am getting a style error:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">.../Sample1/app/src/main/res/values/styles.xml</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(2) Error retrieving parent for item: No resource found that matches the given name 'Theme.AppCompat.Light.DarkActionBar'.</span></div>
</div>
<div>
<br /></div>
<div>
Since there is no appcompat dependency, I've modified AppTheme in styles.xml to have a theme provided by the Android SDK:</div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><style name="AppTheme" parent="android:Theme.Black.NoTitleBar"></font></div>
<div>
<font face="Courier New, Courier, monospace" size="2"> <!-- Customize your theme here. </style></span></div>
<div>
<span courier="" monospace="" new="" quot="" style="font-family: "Courier;"> </span></div>
</div>
<div>
Next error:</div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">
</span><br />
<pre><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">.../Sample1/app/src/main/res/menu/menu_main.xml
Error:(5) No resource identifier found for attribute 'showAsAction' in package 'com.mdzyuba.practice.sample1'
</span></pre>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">
</span>
</div>
<div>
<br />
I just removed app:showAsAction="never" attribute from the menu item element:</div>
<div>
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></span><br />
<pre><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">< item android:id="@+id/action_settings" android:title="@string/action_settings"
android:orderInCategory="100" ></span></pre>
<br />
<br /></div>
<div>
Next, I've got following errors:</div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">.../Sample1/app/src/main/java/com/mdzyuba/practice/sample1/MainActivity.java</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(3, 30) error: package android.support.v7.app does not exist</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(8, 35) error: cannot find symbol class AppCompatActivity</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(10, 5) error: method does not override or implement a method from a supertype</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(12, 9) error: cannot find symbol variable super</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(13, 9) error: cannot find symbol method setContentView(int)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(16, 5) error: method does not override or implement a method from a supertype</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Error:(19, 9) error: cannot find symbol method getMenuInflater()</span></div>
<div>
<br /></div>
<div>
I've removed a dependency on the support lib in MainActivity class:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b>// import android.support.v7.app.AppCompatActivity;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import android.app.Activity;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import android.os.Bundle;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import android.view.Menu;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import android.view.MenuItem;</span></div>
<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;">public class MainActivity extends <b>Activity</b> {</span></div>
</div>
<div>
<br /></div>
<div>
Finally, good news: BUILD SUCCESSFUL :)</div>
<div>
<br /></div>
<div>
Running the app:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-PvoKLtcepMA/VeFSktzrwQI/AAAAAAAAJmg/phj2Y0mAIg0/s1600/device-2015-08-28-233321.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://4.bp.blogspot.com/-PvoKLtcepMA/VeFSktzrwQI/AAAAAAAAJmg/phj2Y0mAIg0/s320/device-2015-08-28-233321.png" width="180" /></a></div>
<div>
<br /></div>
<div>
Hope it might be helpful and save time to anybody else who is creating apps for Amazon Phone with Android Studio.</div>
Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-57029220127785705492015-01-03T01:59:00.001-08:002015-01-03T13:10:39.136-08:00cucumber-jvm and Android Studio<br />
During this Winter holidays, I've been exploring a <a href="http://guide.agilealliance.org/guide/bdd.html">Behavior Driven Development</a> and experimented with a couple of testing frameworks: <a href="http://calaba.sh/">Calabash</a> and <a href="https://github.com/cucumber/cucumber-jvm">cucumber-jvm</a>.<br />
<br />
In this post, I would like to describe setting up cucumber-jvm for Android Studio projects.<br />
<br />
I've extended cucumber-jvm examples with a version for Android Studio. Here is a copy in my github branch:
<a href="https://github.com/mdzyuba/cucumber-jvm/tree/add_android_studio_example/examples/android/android-studio/Cukeulator">https://github.com/mdzyuba/cucumber-jvm/tree/add_android_studio_example/examples/android/android-studio/Cukeulator</a>.<br />
<br />
In addition to the example code, here is some details on how it was created.<br />
<br />
<h3>
Dependencies</h3>
<br />
The cucumber-jvm requires several libraries to be added to a project: <a href="https://github.com/cucumber/cucumber-jvm/tree/master/android">https://github.com/cucumber/cucumber-jvm/tree/master/android</a><br />
<br />
I've found it's easier to add those dependencies with the Android Studio project setup dialog because it takes care of the jar versions for you.<br />
<br />
File > Project Structure > Modules > app > Dependencies > + > Library dependency<br />
> type "cucumber" in the search dialog and submit a search request<br />
> select<br />
cucumber-core.jar,<br />
cucumber-html.jar,<br />
cucumber-java.jar,<br />
cucumber-junit.jar,<br />
cucumber-jvm-deps.jar,<br />
gherkin.jar.<br />
<br />
Make sure to set the scope for the libs as Test compile:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-_qQo3hSDsFs/VKe0p2pog4I/AAAAAAAAFYI/fEGVjD_H2BY/s1600/project_dependencies.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-_qQo3hSDsFs/VKe0p2pog4I/AAAAAAAAFYI/fEGVjD_H2BY/s320/project_dependencies.png" height="231" width="400" /></a></div>
<br />
The cucumber-android.jar contains an apklib. Turns out Android Studio does not support it yet. Please see <a href="https://plus.google.com/+ChristopherBroadfoot/posts/7uyipf8DTau">this post</a> for more details.<br />
<br />
A workaround is to build the jar yourself or just append @jar to the dependency:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">androidTestCompile 'info.cukes:cucumber-android:1.2.0<b><span style="color: blue;">@jar</span></b>'</span><br />
<br />
Note, the `@jar` suffix is required in order to use the embedded jar file.<br />
<br />
If you like to build the jar yourself, make a copy of cucumber-jvm<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">git clone https://github.com/cucumber/cucumber-jvm.git</span><br />
<br />
Build cucumber-android jar following the steps described here:
<a href="https://github.com/cucumber/cucumber-jvm/tree/master/android">https://github.com/cucumber/cucumber-jvm/tree/master/android</a><br />
<br />
Copy the jar:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">cp android/target/cucumber-android-1.2.1-SNAPSHOT.jar you_project/app/libs</span><br />
<br />
Add a dependency on a jar file to your project<br />
<br />
File > Project Structure > Modules > app > Dependencies > + > File dependency<br />
> select the cucumber-android-1.2.1-SNAPSHOT.jar<br />
> select Test compile scope.<br />
<br />
Once this is done, the build.gradle should have something like this:<br />
<br />
<pre><span style="font-family: Courier New, Courier, monospace;">dependencies {
androidTestCompile 'info.cukes:cucumber-core:1.2.0'
androidTestCompile 'info.cukes:cucumber-html:0.2.3'
androidTestCompile 'info.cukes:cucumber-java:1.2.0'
androidTestCompile 'info.cukes:cucumber-junit:1.2.0'
androidTestCompile 'info.cukes:cucumber-jvm-deps:1.0.3'
androidTestCompile 'info.cukes:cucumber-picocontainer:1.2.0'
androidTestCompile 'info.cukes:gherkin:2.12.2'
androidTestCompile 'junit:junit:4.12'
androidTestCompile files('libs/cucumber-android-1.2.1-SNAPSHOT.jar')
}</span>
</pre>
<pre>
</pre>
<pre></pre>
<h3>
<span style="font-size: large;"><b>assets/features</b></span></h3>
<br />
The cucumber tests are stored in a assets/features folder. I placed them under androidTest folder:<br />
<br />
Project/app/src/androidTest/assets<br />
<br />
Then updated build.gradle with assets.srcDirs for androidTest:<br />
<br />
<pre><span style="font-family: Courier New, Courier, monospace;">android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
defaultConfig {
applicationId "cukeulator.android.example.cucumber.cukeulator"
minSdkVersion 19
targetSdkVersion 21
versionCode 1
versionName "1.0"
testApplicationId "cukeulator.android.example.cucumber.cukeulator.test"
testInstrumentationRunner "cucumber.api.android.CucumberInstrumentation"
}
<span style="color: blue;"> sourceSets {
androidTest {
assets.srcDirs = ['src/androidTest/assets']
}
}</span><span style="font-size: x-small;">
</span></span></pre>
<br />
At this point the project should build with no errors.<br />
<br />
<h3>
Test Code</h3>
<br />
The actual tests code is described here:<br />
<a href="https://github.com/cucumber/cucumber-jvm/tree/master/android">https://github.com/cucumber/cucumber-jvm/tree/master/android</a><br />
and in the project examples.<br />
<br />
There are two things required by cucumber-jvm: the tests code should be in the same package as the test packageId, and the test runner should be <span style="font-family: Courier New, Courier, monospace;">cucumber.api.android.CucumberInstrumentation</span>. Therefore, I've added these two lines to the defaultConfig part of the build.gradle:<br />
<br />
<pre><span style="font-family: Courier New, Courier, monospace;"> testApplicationId "cukeulator.android.example.cucumber.cukeulator.test"
testInstrumentationRunner "cucumber.api.android.CucumberInstrumentation"</span>
</pre>
<br />
<h3>
Test Run Configuration</h3>
<br />
In order to create a new test run configuration for cucumber tests in Android Studio, select<br />
<br />
Run > Edit Configurations<br />
Click + and Select Android Tests<br />
Specify:<br />
- Test name: CalculatorTest<br />
- Module: app<br />
- Specific instrumentation runner: cucumber.api.android.CucumberInstrumentation<br />
Click Ok<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-7ATOF0lvWx0/VKe7N-ww_wI/AAAAAAAAFYY/NVbKiuoYqro/s1600/test_setup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-7ATOF0lvWx0/VKe7N-ww_wI/AAAAAAAAFYY/NVbKiuoYqro/s1600/test_setup.png" height="256" width="400" /></a></div>
<br />
<br />
If you like, you can run the tests from a command line:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">cd your_project_folder</span><br />
<span style="font-family: Courier New, Courier, monospace;">./gradlew connectedCheck</span><br />
<h3>
Test Run Results</h3>
<br />
The test results are displayed in the Android Studio:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-vMzt6hkoNyM/VKe7rMjUmeI/AAAAAAAAFYg/iMEo37iwqDY/s1600/test_passing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-vMzt6hkoNyM/VKe7rMjUmeI/AAAAAAAAFYg/iMEo37iwqDY/s1600/test_passing.png" height="388" width="640" /></a></div>
<br />Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com1tag:blogger.com,1999:blog-7082684402140657004.post-25029109588068758582009-11-25T23:33:00.000-08:002009-11-25T23:36:15.411-08:00Flash on Google SitesThis is a brief how-to add a Flash on a Google Site.<br />
<br />
Google Sites allows adding Flash embedded into a Google Gadget. I uploaded a swf file to my Google Site - <a href="http://sites.google.com/site/flexwebtools/">FlexWebTools</a> and found a gadget that allows displaying any SWF on a Google Site page. It is called AnyFlash. It is pretty easy to use and it worked fine in my Firefox 3.5.5 on Mac OS X 10.5.8. Then I send a link to my site to my friends and they discovered that the SWF was not displayed properly on IE6 and in Firefox on Linux. I reviewed AnyFlash source code and eventually found that there is a <a href="http://code.google.com/p/opensocial-resources/issues/detail?id=939">bug 939</a> in the Google Gadget API. Therefore, I created a new gadget that does not use the gadgets.flash.embedFlash() method and works well with Firefox, Safari and IE6 browsers on Mac, Windows and Linux. <br />
<br />
While working on the gadget, I found a few different ways of embedding Flash into a gadget. Some of them are pretty straightforward like simply pointing to a swf in the context tag. Some are more sophisticated. For instance, they would display images while SWF is loading, provide controls to start the application, etc. The source code for public Google Gadgets is available for preview. It is really fun to read and there are a lot of interesting stuff in the plugins code. <br />
<br />
I compared a few SWF embedding options and decided to use <a href="http://code.google.com/p/swfobject/">SWFObject 2 API</a> because it comes with lots of pretty helpful features that ensure a smooth SWF loading. By the way, it is used by Flash Builder too. So, I created a gadget called <a href="http://hosting.gmodules.com/ig/gadgets/file/115416676993110640302/FlashWrapper.xml">FlashWrapper</a>. It is public and anyone is welcome to use it. <br />
<br />
The setup and configuration is pretty easy. Once you add it to your page, the page will display a dialog where you can specify your SWF URL, the width and height of the SWF, the minimum required browser version (optional), the the background color (optional). The SWF could be stored on a Google Site, or on any other site.<br />
<br />
Please let me know if you find any bugs or experience any problems with it. I hope FlashWrapper will be useful.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com3tag:blogger.com,1999:blog-7082684402140657004.post-9694334041680761162008-05-22T23:28:00.000-07:002008-05-23T00:46:33.444-07:00Testing Remote Data Services with FlexUnit<p>This is a short example that describes an approach on testing a Flex remote data access code with <a href="http://code.google.com/p/as3flexunitlib/">FlexUnit</a>. The access to the remote services in Flex is provided via <a href="http://livedocs.adobe.com/flex/3/langref/mx/rpc/http/HTTPService.html">HTTPService</a>, <a href="http://livedocs.adobe.com/flex/3/langref/mx/rpc/soap/WebService.html">WebService</a> or <a href="http://livedocs.adobe.com/flex/3/langref/mx/rpc/remoting/mxml/RemoteObject.html">RemoteObject</a> classes. The requests to the data services are handled asynchronously. That adds a bit more complexity to the unit testing. In this example, I will share a design idea on how to test a client side of the remote data services. This is something I came up with working on my "pet" project.</p><br /><p>The "pet" project is a Web application that is based on a three tier architecture: an SQL database, a middleware part implemented with Java, Hibernate, and BlazeDS, and a client tier implemented with Flex. The example shown here works on a client side and tests access to the server-side part of the application. The tests covered in this example are designed to test a user login operation.</p><br /><p>The login operation is defined on the server-side class called UserService. </p><br /><pre>public class UserService {<br /><br /> /**<br /> * User login operation.<br /> *<br /> * @param username<br /> * the user name.<br /> * @param password<br /> * the password.<br /> * @return a User object or null if username is not found or password is not<br /> * valid.<br /> */<br /> public User login(String username, String password) {<br /> User user = null;<br /> Session session = HibernateUtil.getSessionFactory().openSession();<br /> Transaction tx = session.beginTransaction();<br /> List users = session.createQuery(<br /> "from User user where user.username = ?")<br /> .setString(0, username).list();<br /> if (users.size() == 1) {<br /> user = (User) users.get(0);<br /> }<br /><br /> if (user != null && user.isPasswordValid(password)) {<br /> Hibernate.initialize(user);<br /> // trying to fetch the lazy loaded items<br /> user.getProjects().size();<br /> for (Project p : user.getProjects()) {<br /> p.getTasks().size();<br /> }<br /> // return user<br /> } else {<br /> // return null<br /> user = null;<br /> }<br /><br /> tx.commit();<br /> session.close();<br /><br /> return user;<br /> }<br />}</pre><br /><p>The UserService service is configured as a BlazeDS destination in remoting-confix.xml:</p><br /><pre><?xml version="1.0" encoding="UTF-8"?><br /><service id="remoting-service"<br /> class="flex.messaging.services.RemotingService"><br /> <adapters><br /> <br /><adapter-definition id="java-object"<br />class="flex.messaging.services.remoting.adapters.JavaAdapter"<br />default="true"/><br /> </adapters><br /> <default-channels><br /> <channel ref="my-amf"/><br /> </default-channels><br /> <destination id="user"><br /> <properties><br /> <source>org.blazedspractice.model.UserService</source><br /> <scope>request</scope><br /> </properties><br /> </destination><br /></service></pre><br /><br /><br /><p>The FlexUnit test code shown below is invoking the UserService login method through a RemoteObject class and validates the response. We will review just a couple of test cases: a positive one, i.e. a valid user ID/password combination and a negative, that tests a login operation with an invalid password. The database is initialized with a test user account before the test run. Here is the code:</p><br /><pre>package org.blazedspractice.model<br />{<br /> import flash.events.Event;<br /> import flash.events.TimerEvent;<br /> import flash.utils.Timer;<br /> <br /> import flexunit.framework.TestCase;<br /> import flexunit.framework.TestSuite;<br /> <br /> import mx.rpc.events.FaultEvent;<br /> import mx.rpc.events.ResultEvent;<br /> import mx.rpc.remoting.RemoteObject; <br /> <br /> public class UserTest extends TestCase {<br /> private static const LOGIN_NAME:String = "user1";<br /> private static const LOGIN_PSW:String = "password";<br /> private static const INVALID_LOGIN_PSW:String = "invalid_password";<br /><br /> private var user:User;<br /> private var fault:Boolean = Boolean(false);<br /> private var resultCheckTimer:Timer;<br /> <br /> // The timer and result check timeouts<br /> private static const TIMEOUT_MS:int = 3000;<br /> private static const RESULT_CHECK_TIMEOUT_MS:int = 3500;<br /> <br /> /**<br /> * The test case constructor.<br /> * @param The name of the test method to be called in the test run.<br /> */<br /> public function UserTest(methodName:String) {<br /> super( methodName );<br /> }<br /><br /> /**<br /> * Builds a test suite.<br /> */<br /> public static function suite():TestSuite {<br /> var ts:TestSuite = new TestSuite();<br /> ts.addTest( new UserTest( "testLogin" ) );<br /> ts.addTest( new UserTest( "testLoginNegative" ) );<br /> return ts;<br /> }<br /> <br /> /**<br /> * Setup the test. This method is executed before every testXXX() by the framework.<br /> */<br /> override public function setUp() : void {<br /> user = null;<br /> fault = Boolean(false);<br /> }<br /><br /> /**<br /> * This test case validates login operation. The login name and password are valid.<br /> */<br /> public function testLogin():void {<br /> // Create a remote object<br /> var userService:RemoteObject = new RemoteObject();<br /> // This is a name of the destination configured in BlazeDS settings<br /> userService.destination = "user";<br /> // Add result and fault event listeners as asynchronous checkpoints<br /> userService.login.addEventListener("result", handleLoginResponse);<br /> userService.addEventListener("fault", faultHandler);<br /> // Create a timer that will validate a result of the login operation.<br /> resultCheckTimer = new Timer(1);<br /> resultCheckTimer.delay = TIMEOUT_MS;<br /> resultCheckTimer.addEventListener(TimerEvent.TIMER, addAsync(loginCheck, RESULT_CHECK_TIMEOUT_MS));<br /> resultCheckTimer.start();<br /> // Call the login method. <br /> userService.login(LOGIN_NAME, LOGIN_PSW);<br /> }<br /><br /> /**<br /> * This method handles login response event. It is invoked by the<br /> * Flex framework once the server side data service returns a response to<br /> * the login request.<br /> */<br /> private function handleLoginResponse(event:ResultEvent):void {<br /> user = event.result as User;<br /> trace("user: " + user);<br /> }<br /><br /> private function faultHandler (event:FaultEvent):void {<br /> fault = Boolean(true);<br /> fail(event.fault.faultString);<br /> }<br /> <br /> /**<br /> * Validate a positive test case.<br /> */<br /> private function loginCheck(event:Event):void {<br /> resultCheckTimer.reset();<br /> trace("loginCheck: " + user);<br /> if (fault == Boolean(true)) {<br /> fail("login failed");<br /> }<br /> assertNotNull(user);<br /> assertNotUndefined(user);<br /> }<br /><br /> /**<br /> * The negative test case. The login password is invalid.<br /> */<br /> public function testLoginNegative():void {<br /> var userService:RemoteObject = new RemoteObject();<br /> userService.destination = "user";<br /> userService.login.addEventListener("result", handleLoginResponse);<br /> userService.addEventListener("fault", faultHandler);<br /> <br /> resultCheckTimer = new Timer(1);<br /> resultCheckTimer.delay = TIMEOUT_MS;<br /> resultCheckTimer.addEventListener(TimerEvent.TIMER, addAsync(loginFailureCheck, RESULT_CHECK_TIMEOUT_MS));<br /> resultCheckTimer.start();<br /> <br /> userService.login(LOGIN_NAME, INVALID_LOGIN_PSW);<br /> }<br /> <br /> /**<br /> * Validate a negative test case.<br /> */<br /> private function loginFailureCheck(event:Event):void {<br /> resultCheckTimer.reset();<br /> trace("loginCheck: " + user);<br /> if (fault == Boolean(true)) {<br /> fail("login failed");<br /> }<br /> assertNull(user);<br /> }<br /> }<br />}<br /></pre><br /><p>The comments in the code explain the low level details of the test. The <a href="http://code.google.com/p/as3flexunitlib/">FlexUnit</a> and <a href="http://livedocs.adobe.com/flex/3/langref/index.html">Flex SDK API</a> documentation will cover the rest. I will explain why do we need a timer here and what is addAsync for. :) That is the key to the solution.</p><br /><p>The call to userService.login(LOGIN_NAME, LOGIN_PSW); will submit a request to the remote data service and return immediately, since it is an asynchronous call. The response from the userService.login() call will be handled as an event. The call to the service could be successful or could fail due to a system error, for example the network connection is not available or a service is not configured properly, etc. These cases are handled as "result" and "fault:" event types:</p><br /><pre>userService.login.addEventListener("result", handleLoginResponse);<br />userService.addEventListener("fault", faultHandler);</pre><br /><p>The faultHandler() method will be invoked by the Flex SDK framework in case of a system error while calling the data service. The handleLoginResponse() method will be invoked when the response is received successfully. </p><br /><p>The test should validate the response and assert expected values based on the test scenario. It should also fail in case of a system error.</p><br /><p>The FlexUnit invokes just the methods starting with "test" prefix. Usually a test will be considered to be complete as soon as the testXXX() method is complete. However, we need to validate the results of the login operation that could be available in a few milliseconds after the testXXX() is done. To handle that case, FlexUnit provids a method that is called addAsync. The addAsync is defined in TestCase.as class of the FlexUnit framework:</p><br /><pre>/**<br />* Add an asynchronous check point to the test.<br />* This method will return an event handler function.<br />*<br />* @param func the Function to execute when things have been handled<br />* @param timeout if the function isn't called within this time the test is considered a failure<br />* @param passThroughData data that will be passed to your function (only if non-null) as the 2nd argument<br />*<br />@param failFunc a Function that will be called if the asynchronous<br />function fails to execute, useful if perhaps the failure to<br />* execute was intentional or if you want a specific failure message<br />* @return the Function that can be used as an event listener<br />*/<br /><br />public function addAsync(func : Function, timeout : int,<br />passThroughData : Object = null, failFunc : Function = null) : Function<br /> {<br /> if (asyncTestHelper == null)<br /> {<br /> asyncTestHelper = new AsyncTestHelper(this, testResult);<br /> }<br /> asyncMethods.push({func: func, timeout: timeout, extraData: passThroughData, failFunc: failFunc});<br /> return asyncTestHelper.handleEvent;<br /> }</pre><br /><p>Basically addAsync adds a delayed check point to the test validation. Internally, the AsyncTestHelper class schedules a timer to do that.</p><br /><p>Why does our test need a timer too? I guess, we could simply wrap our event handlers with the addAsync() like this:</p><br /><pre> userService.login.addEventListener("result", addAsync(handleLoginResponse, RESULT_CHECK_TIMEOUT_MS));<br />userService.addEventListener("fault", addAsync(faultHandler, RESULT_CHECK_TIMEOUT_MS));<br /></pre><br /><p>Well, that will work for the handleLoginResponse case, but will create a problem for faultHandler. In case of a successful response from the service, the timer scheduled internally by addAsync will time out, and the test will fail with an exception saying that method faultHandler() was never called. I suppose, I coudl cancel one of the timers if I get either one of the async points. However, I don't have an access to those timers and I don't want to make the tests to be too dependent on the internal implementation of the FlexUnit. Therefore, I introduced a local timer that invokes a method in a RESULT_CHECK_TIMEOUT_MS time and validates results set by data service result handlers. For example, testLogin() method schedules a call to loginCheck() method. The loginCheck() validates class variables called fault and user that are initialized in the data service result handlers handleLoginResponse() and faultHandler(). This is the basic idea.</p><br /><p>The test runner is based on one I described in the earlier post. Here is its source code:</p><br /><pre><?xml version="1.0" encoding="utf-8"?><br /><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"<br /> xmlns:flexunit="flexunit.flexui.*"<br /> creationComplete="onCreationComplete()"><br /> <mx:Script><br /> <![CDATA[<br /> import flexunit.framework.TestSuite;<br /> import flexunit.flexui.TestRunnerBase;<br /> import mx.collections.ArrayCollection;<br /><br /> import org.blazedspractice.model.UserTest;<br /> <br /> [Bindable]<br /> public var testClients:ArrayCollection;<br /> <br /> public var NUMBER_OF_TESTS:int = 1;<br /> <br /> private function onCreationComplete():void<br /> {<br /> var clients:Array = new Array();<br /> var i:int;<br /> for (i = 0; i < NUMBER_OF_TESTS; i++) {<br /> clients.push("test"+i);<br /> }<br /> testClients = new ArrayCollection(clients);<br /> startTests();<br /> }<br /> <br /> // Creates the test suite to run<br /> private function createSuite():TestSuite {<br /> var ts:TestSuite = new TestSuite();<br /><br /> ts.addTest( UserTest.suite() );<br /> <br /> return ts;<br /> }<br /> <br /> private function startTests():void {<br /> trace(" elements: " + testRepeater.numChildren);<br /> var tests:Array = this.test as Array;<br /> for each (var testRunner:TestRunnerBase in tests) {<br /> testRunner.test = createSuite();<br /> testRunner.startTest();<br /> }<br /> }<br /> <br /> ]]><br /> </mx:Script><br /><br /> <mx:Button name="Run" label="Start Tests" click="startTests()" /><br /><br /> <mx:Panel layout="vertical" width="100%" height="100%"><br /> <mx:Repeater id="testRepeater" dataProvider="{testClients}"><br /> <flexunit:TestRunnerBase id="test" width="100%" height="100%" /><br /> </mx:Repeater><br /> </mx:Panel><br /></mx:Application></pre><br /><p>Since the test runner is a Flex application, the build and deployment is the same as for the main application. I actually deply it together with the main application. Here is my ant target that creates html wrappers for the application itself and the test runner:</p><br /><pre> <target name="compile.flex" depends="init, compile.flex.components, compile.flex.mxml, compile.flex.tests"><br /> <html-wrapper title="${APP_TITLE}" file="index.html" application="app"<br /> swf="${module}" version-major="9" version-minor="0" version-revision="0"<br /> width="90%" height="100%" history="true" template="express-installation"<br /> output="${build.dir}/${ant.project.name}/" /><br /> <html-wrapper title="${APP_TITLE}" file="test.html" application="testapp"<br /> swf="TestRunner" version-major="9" version-minor="0" version-revision="0"<br /> width="90%" height="100%" history="true" template="express-installation"<br /> output="${build.dir}/${ant.project.name}/" /><br /> </target></pre><br /><p>To run the tests, I simply navigate to the URL with the test.html, in my case it is<br />http://localhost:8400/blazeds_practice2/test.html. The tests are run automatically on the page creationComple event. The "Start Tests" button can be used to run them again. Here are the run results:</p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_ZC88Bkj8_e0/SDZt_7YutVI/AAAAAAAAABc/hq0t9HC34kQ/s1600-h/FlexUnitScreen2.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_ZC88Bkj8_e0/SDZt_7YutVI/AAAAAAAAABc/hq0t9HC34kQ/s400/FlexUnitScreen2.png" alt="" id="BLOGGER_PHOTO_ID_5203467364513789266" border="0" /></a><br /><p>I hope this article will be helpful. I am sure this approach can be improved. The code I posted here does not cover all the conditions and most probably contains a few errors. I do not recommend using it as is in production. The intent was to share an idea and get some feedback. I am sure the approach described here is just one of the possible ways. I would be interested to learn more about testing asynchronous code and open to your comments and suggestions.</p>Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com1tag:blogger.com,1999:blog-7082684402140657004.post-58466343465712592572008-05-20T23:58:00.000-07:002008-05-21T00:31:07.595-07:00Building a Flex project with Ant<p>Here is a quick sample on how to build a simple Flex<br />"hello world" project with Ant. </p>The "hello world" project contains a src folder with one Flex application file and an Ant build.xml file:<br /><pre><br />./project_home/<br /> ./src/<br /> app.mxml<br /> build.xml<br /></pre><br /><p>The app.mxml is the main module of the project. It simply has a label with a "Hello World!" text:</p><pre><?xml version="1.0" encoding="utf-8"?><br /><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"><br /><mx:Label text="Hello World!"/><br /></mx:Application><br /></pre>Here is the build.xml source:<br /><pre><?xml version="1.0"?><br /><project name="fx_practice7" default="all"><br /><br /> <!-- Init the build process --><br /> <target name="init" unless="initialized"><br /> <!-- Name of project and version --><br /> <property name="FLEX_HOME" location="/Users/mykola/java/flex"/><br /><br /> <property name="proj.name" value="${ant.project.name}" /><br /> <property name="proj.shortname" value="${ant.project.name}" /><br /> <property name="version.major" value="0" /><br /> <property name="version.minor" value="9" /><br /> <property name="version.revision" value="0" /><br /> <property name="APP_TITLE" value="Sample Application" /><br /> <property name="APP_WIDTH" value="800" /><br /> <property name="APP_HEIGHT" value="600" /><br /> <br /> <!-- Global properties for this build --><br /> <property name="build.dir" location="${basedir}/build" /><br /> <property name="flex_src" location="${basedir}/src" /><br /><br /> <path id="project.classpath"><br /> <pathelement path="${java.class.path}" /><br /> </path><br /> <br /> <taskdef resource="flexTasks.tasks"<br /> classpath="${FLEX_HOME}/ant/lib/flexTasks.jar" /><br /> <br /> <echoproperties/><br /><br /> <property name="initialized" value="true" /><br /> <br /> <mkdir dir="${build.dir}" /><br /> </target><br /><br /> <!-- Default target: clean and build the application --><br /> <target name="all" depends="init"><br /> <antcall target="clean" /><br /> <antcall target="build" /><br /> </target><br /><br /> <!-- Compile Flex files --><br /> <target name="compile.flex" depends="init"><br /> <property name="module"<br /> value="${ant.project.name}"<br /> description="The name of the application module." /><br /><br /> <mxmlc file="${flex_src}/${module}.mxml"<br /> keep-generated-actionscript="true"<br /> output="${build.dir}/${ant.project.name}/${module}.swf"<br /> actionscript-file-encoding="UTF-8"<br /> incremental="true"<br /> context-root="${ant.project.name}"<br /> debug="true"><br /> <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml" /><br /> <source-path path-element="${FLEX_HOME}/frameworks" /><br /> <compiler.source-path path-element="${flex_src}" /><br /> </mxmlc><br /><br /> <html-wrapper title="${APP_TITLE}"<br /> file="index.html"<br /> application="app"<br /> swf="${module}"<br /> width="${APP_WIDTH}"<br /> height="${APP_HEIGHT}"<br /> version-major="${version.major}"<br /> version-minor="${version.minor}"<br /> version-revision="${version.revision}"<br /> history="true"<br /> template="express-installation"<br /> output="${build.dir}/${ant.project.name}/" /><br /><br /> </target><br /><br /> <!-- Build the application --><br /> <target name="build" depends="init"><br /> <antcall target="compile.flex" /><br /> </target><br /><br /> <!-- Clean build files --><br /> <target name="clean" depends="init"><br /> <delete dir="${basedir}/generated" /><br /> <delete dir="${build.dir}" /><br /> </target><br /><br /> <target name="usage" description="Usage documentation"><br /> <echo><br /> all - clean and build the project<br /> </echo><br /> </target><br /></project></pre>NOTE: Please update FLEX_HOME and other properties in the build.xml as required for your environment.<br /><br />To do the build, simply run ant in the project folder. The build output will be stored in the project/build/ folder. To see the result, open index.html in a browser. The index.html is located in the project/build/project_home/ folder.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com4tag:blogger.com,1999:blog-7082684402140657004.post-21477266073722132602008-05-19T19:41:00.000-07:002008-05-21T00:31:37.020-07:00Using FlexUnit for Stress Testing<p>I saw quite a few questions in the forums on how to stress<br />test a Flex application. I thought about it and came up with an idea<br />that I want to share here. </p><br /><br /><br /><p>I think FlexUnit can be used for stress testing. It is not<br />that difficult. I simply add multiple test runners for each client<br />application and run all of them asynchronously. Here is the example of<br />the FlexUnit runner:</p><br /><br /><br /><pre><?xml version="1.0" encoding="utf-8"?><br /><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"<br /> xmlns:flexunit="flexunit.flexui.*"<br /> creationComplete="onCreationComplete()"><br /><br /><mx:Script><br /> <![CDATA[<br /> import flexunit.framework.TestSuite;<br /> import test.TemperatureConverterTest;<br /> import test.ArrayUtilTest;<br /> import mx.collections.ArrayCollection;<br /> import flexunit.flexui.TestRunnerBase;<br /> <br /> [Bindable]<br /> public var testClients:ArrayCollection;<br /> <br /> public var NUMBER_OF_TESTS:int = 100;<br /> <br /> private function onCreationComplete():void<br /> {<br /> var clients:Array = new Array();<br /> var i:int;<br /> for (i = 0; i < NUMBER_OF_TESTS; i++) {<br /> clients.push("test"+i);<br /> }<br /> testClients = new ArrayCollection(clients);<br /> }<br /> <br /> // Creates the test suite to run<br /> private function createSuite():TestSuite {<br /> var ts:TestSuite = new TestSuite();<br /><br /> ts.addTest( TemperatureConverterTest.suite() );<br /> ts.addTest( ArrayUtilTest.suite() );<br /> <br /> return ts;<br /> }<br /> <br /> private function startTests():void {<br /> trace(" elements: " + testRepeater.numChildren);<br /> var tests:Array = this.test as Array;<br /> for each (var testRunner:TestRunnerBase in tests) {<br /> testRunner.test = createSuite();<br /> testRunner.startTest();<br /> }<br /> }<br /> <br /> ]]><br /></mx:Script><br /><br /><mx:Button name="Run" label="Start Tests" click="startTests()" /><br /><br /><mx:Panel layout="vertical" width="100%"><br /> <mx:Repeater id="testRepeater" dataProvider="{testClients}"><br /> <flexunit:TestRunnerBase id="test" width="100%" height="100%" /><br /> </mx:Repeater><br /><br /></mx:Panel><br /></mx:Application><br /><br /><br /></pre><br /><br /><br /><p><br />Here is a screen shot of the test with 100 test runners:</p><br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_ZC88Bkj8_e0/SDI7DAv9PQI/AAAAAAAAABU/ryFoArW3L1M/s1600-h/FlexUnitScreen1.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_ZC88Bkj8_e0/SDI7DAv9PQI/AAAAAAAAABU/ryFoArW3L1M/s400/FlexUnitScreen1.png" alt="" id="BLOGGER_PHOTO_ID_5202285442493136130" border="0" /></a><br /><p>So, I guess once you have a client application that runs<br />hundreds of tests in parallel, it is easy to launch it on several<br />instances of the browser, or even on several PCs. All you need to do is<br />to add startTests() call to onCreationComplete() as a last<br />line of the method, deploy the app and simply open the URL in the<br />browsers.</p><br /><p>The other nice thing about it is that this test client can be<br />used for profiling purposes. FlexBuilder has a very nice profiler. I<br />found it very helpful in testing my BlazeDS application.</p>Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com7tag:blogger.com,1999:blog-7082684402140657004.post-57468054015659335832008-04-25T19:39:00.000-07:002008-04-25T19:51:11.448-07:00Java and Flex Builder 3<p><br />Flex Builder 3 is distributed as an Eclipse plugin and as a standalone IDE. The standalone version does not support Java development out of the box. These couple of blogs helped me to add Java to the standalone version.<br /></p><br /><br /><ul><li><a href="http://blogs.adobe.com/flexdoc/2008/04/adding_java_development_tools_1.html">Adding Java Development Tools to Flex Builder Standalone</a> by Flex Doc Team</li></ul><br /><ul><li><a href="http://www.nodans.com/index.cfm/2007/10/8/Adding-Subclipse-to-Flex-Builder-3-Standalone">Adding Subclipse to Flex Builder 3 Standalone</a> by Dan Wilson</li></ul>Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com1tag:blogger.com,1999:blog-7082684402140657004.post-80705715756264312592008-03-15T23:21:00.000-07:002008-03-16T00:38:01.624-07:00Setting a default application for Flex SWF files on Mac<p><br />I found a small problem with opening SWF files on Mac. I am using Mac OS X Tiger version at the moment. I installed Flex SDK 3 and created a sample project in Eclipse with an Ant build file that compiles my Flex msml code to SWF files. I've noticed that generated SWF files are associated with RealPlayer, however it does not really play them.<br /></p><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_ZC88Bkj8_e0/R9y_Xzp1V9I/AAAAAAAAABM/xf6MNHmu1PQ/s1600-h/RealPlayerMessage.jpg"><img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://bp2.blogger.com/_ZC88Bkj8_e0/R9y_Xzp1V9I/AAAAAAAAABM/xf6MNHmu1PQ/s320/RealPlayerMessage.jpg" alt="" id="BLOGGER_PHOTO_ID_5178224087292794834" border="0" /></a><br /><br /><p><br />I can select these files in Firefox just fine. But, the bigger problem is when I use a command line Flex debugging tool called fdb. It opens the RealPlayer for me, and I cannot really choose a player in the <span style="font-weight: bold;">fdb</span> tool.<br /></p><br /><br /><pre><br />Adobe fdb (Flash Player Debugger) [build 814]<br />Copyright (c) 2004-2007 Adobe, Inc. All rights reserved.<br />(fdb) <br />(fdb) run file:///Users/mykola/progs/workspace2/fx_practice3/build/fx_practice3.swf<br />Attempting to launch and connect to Player using URL<br />file:///Users/mykola/progs/workspace2/fx_practice3/build/fx_practice3.swf<br /></pre><br /><br /><p><br />Here is how to fix it.<br /></p><ol><li>Open Finder and locate the file with swf extension.<br /></li><li>Right click and select Get Info.<br /></li><li>In the Get Info dialog, select Open with: Other ...<br /></li><li>In the Choose Other Application dialog, set Enable: All Applications and select Firefox or other application you like to play SWF files.<br /></li><li>Click Add. The selected application will be displayed in the Get Info dialog.<br /></li><li>The last step is click on Change All... to set this player application for all SWF files.<br /></li></ol>Done! :)Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-78276596892071063952008-02-18T20:52:00.000-08:002008-02-18T22:16:15.503-08:00How to debug SOAP on Mac with tcpdumpI’ve been using several tools to debug SOAP on Mac and Windows. I would like to share my experience in using some of the tools and show some examples.<br /><br />So far I found four major categories of tools that are useful in debugging SOAP:<br /><ol><li>Interface listeners such as tcpdump and others</li><li>Proxy tools such as TCPMonitor</li><li>Servlet filters</li><li>Application server logging. For example, Weblogic has a special logging option that dumps SOAP requests and responses to the sever log.<br /></li></ol>All of these tools have their own advantages and disadvantages. In this article, I will describe the first type - an interface listener tool called tcpdump. I am planning to describe other three categories in the future posts.<br /><br />The <span style="font-weight: bold;">tcpdump</span> is a tool that sniffs IP traffic and dumps it to a file or a standard output stream. It was originally developed by Van Jacobson, Craig Leres and Steven McCanne from the Lawrence Berkeley National Laboratory, University of California, Berkeley, CA. It is open source. The <span style="font-style: italic;font-family:courier new;" >tcpdump</span> documentation and source code is available at <a href="http://www.tcpdump.org/">http://www.tcpdump.org/</a>. The <span style="font-style: italic;font-family:courier new;" >tcpdump</span> has been ported to many platforms. The version for Mac comes with MacPorts ( <a href="http://www.macports.org/">http://www.macports.org/</a>).<br /><br />Here is an example of capturing SOAP traffic where the service is deployed on the local host:<br /><br /><span style="color: rgb(0, 0, 153); font-family: courier new;">$ sudo tcpdump -i lo0 -A -s 1024 -l 'dst host localhost and port 8080' | tee dump.log</span><br /><br />I use <span style="font-style: italic;font-family:courier new;" >sudo</span> because <span style="font-style: italic;font-family:courier new;" >tcpdump</span> requires root privileges to run. In this example, the <span style="font-family: courier new;">tcpdump</span> listens to the <a href="http://en.wikipedia.org/wiki/Loopback">loopback interface</a> defined on my Mac as lo0 and pipes out the data to dump.log file. To see all available interfaces, run ifconfig or tcpdump with –D option.<br /><br />The Web service I use in this example is deployed on an instance of Glassfish Open Source Application Server for J2EE 5 (<a href="https://glassfish.dev.java.net/">https://glassfish.dev.java.net/</a>). It has a couple of methods:<br /><br /><pre><br />/**<br />* Coffee Shop service.<br />*<br />* @author mykola<br />*/<br />@WebService()<br />public class CoffeeShop {<br />@WebMethod<br />public String getName() {<br /> return "CoffeeShop, Inc.";<br />}<br /><br />@WebMethod<br />@WebResult(name="price")<br />public int placeOrder(<br /> @WebParam(name="product")<br /> String product) {<br /> int price = -1;<br /> if ("coffee".equalsIgnoreCase(product)) {<br /> price = 2;<br /> } else if ("cake".equalsIgnoreCase(product)) {<br /> price = 5;<br /> }<br /> return price;<br />}<br />}<br /></pre><br /><br />I created a client application and once I call getName() Web service method I’ve got these SOAP request and response in the dump.log file:<br /><br /><br />Request:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_ZC88Bkj8_e0/R7phmA3POiI/AAAAAAAAAA8/IwvZYsLTo64/s1600-h/request"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_ZC88Bkj8_e0/R7phmA3POiI/AAAAAAAAAA8/IwvZYsLTo64/s400/request" alt="" id="BLOGGER_PHOTO_ID_5168550828055673378" border="0" /></a><br /><br /><br />Response:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_ZC88Bkj8_e0/R7piIw3POjI/AAAAAAAAABE/EG4aWWnsMAM/s1600-h/response"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_ZC88Bkj8_e0/R7piIw3POjI/AAAAAAAAABE/EG4aWWnsMAM/s400/response" alt="" id="BLOGGER_PHOTO_ID_5168551425056127538" border="0" /></a><br /><br />The tcpdump logs lots of data. For SOAP debugging, we are interested in the <S:Envelope> content and HTTP headers.<br /><br />This is a quick and dirty way of getting raw SOAP on the wire. The advantage of this approach is that it is not intrusive, i.e. no special client or service configuration is required. It does not affect performance of the web service or the client. It logs every byte in the message, even control symbols, which could be a disadvantage in some cases. The tcpdump would be very hard to use for debugging SOAP over HTTPS. Also, this approach is hard to use in cases where automated SOAP validation is required. I use filters for that. This is a topic for a future post.<br /><br />I hope this post was helpful. Please let me know if you have any questions or comments. Thank you for reading.<br /><br /><p/><br /><script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script>Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-6681878113760815682008-02-15T15:52:00.000-08:002008-02-18T22:15:30.748-08:00Deploying BlazeDS to Weblogic 10.0<p class="MsoNormal">The BlazeDS is a free and open source J2EE application that provides data services to Adobe Flex and AIR applications. I’ve deployed it to Weblogic 10.0 server. I thought somebody else would be interested to do the same. Here is how.<o:p></o:p></p><p class="MsoNormal"><o:p></o:p>In case you need to install Weblogic 10.0, the developers copy is available for free at <span style="font-size:85%;"><a href="http://commerce.bea.com/products/weblogicplatform/weblogic_prod_fam.jsp">http://commerce.bea.com/products/weblogicplatform/weblogic_prod_fam.jsp</a>.</span></p> <p class="MsoNormal"><o:p></o:p>I have it installed on my Windows XP at <span style="font-style: italic;font-size:100%;" >D:\bea10</span> folder.<o:p></o:p></p><p class="MsoNormal"><o:p></o:p>I have created a new domain for my BlazeDS applications. It is easy to do, see <span style="font-size:85%;"><a href="http://edocs.bea.com/common/docs100/confgwiz/index.html">http://edocs.bea.com/common/docs100/confgwiz/index.html</a></span> for details.</p> <p class="MsoNormal"><o:p></o:p>In my case, the domain name is <b style="">blazeds</b> and it is located in <span style="font-style: italic;">D:\bea10\user_projects\domains\blazeds</span> folder on my computer. The domain name and the folders names can be difference, I just mentioned them so it is easier to follow the examples..</p> <p class="MsoNormal"><o:p></o:p>Once the Weblogic server is installed and a domain is ready, the BlazeDS applications can be deployed. </p> <p class="MsoNormal"><o:p></o:p>A copy of BlazeDS is available at <span style="font-size:85%;"><a href="http://labs.adobe.com/technologies/blazeds/">http://labs.adobe.com/technologies/blazeds/</a></span>. I downloaded the latest version - <span style="font-style: italic;">blazeds_b1_020108.zip</span> and unzipped it to <span style="font-style: italic;">D:\java\blazeds_b1_020108</span>. </p> <p class="MsoNormal"><o:p></o:p>There are three WAR files provided in BlazeDS distribution: <span style="font-style: italic;">blazeds.war</span>, <span style="font-style: italic;">ds-console.war</span>, and <span style="font-style: italic;">samples.war</span>. Copy them to autodeploy folder of your Weblogic domain. In my case it is <span style="font-style: italic;">D:\bea10\user_projects\domains\blazeds\autodeploy</span>.</p> <p class="MsoNormal"><o:p></o:p>Start the Weblogic servert. If you run it on Windows, simply click on <span style="font-style: italic;">Start -> All Programms -> BEA Products -> User Projects –> blazeds (or your domain name) -> Start Admin Server</span>.</p> <p class="MsoNormal"><o:p></o:p>If everything ok, the Weblogic server log window will appear on the desktop:</p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_ZC88Bkj8_e0/R7Ym9k6QfxI/AAAAAAAAAAU/UHMb5AnpqXQ/s1600-h/WLS1.PNG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_ZC88Bkj8_e0/R7Ym9k6QfxI/AAAAAAAAAAU/UHMb5AnpqXQ/s400/WLS1.PNG" alt="" id="BLOGGER_PHOTO_ID_5167360461776125714" border="0" /></a>Now is a good time to verify that the BlazeDS applications were deployed successfully. It is easy to do by checking the status of the applications in the Weblogic Admin console and scanning the log files for errors. <p class="MsoNormal">My server is configured with HTTP port 7001. My Weblogic console URL is <span style=""> </span><a href="http://localhost:7001/console">http://localhost:7001/console</a>. The console application asks for the admin’s name and password. Just want to remind that they were specified during the domain configuration step. Once you logged in, select Deployments in the Domain Structures window. You should see these applications deployed</p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_ZC88Bkj8_e0/R7YnMU6QfyI/AAAAAAAAAAc/LnokOBk1HqU/s1600-h/WLS2.PNG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_ZC88Bkj8_e0/R7YnMU6QfyI/AAAAAAAAAAc/LnokOBk1HqU/s400/WLS2.PNG" alt="" id="BLOGGER_PHOTO_ID_5167360715179196194" border="0" /></a> <p class="MsoNormal">I also like to check the log files for errors. The BlazeDS log file is created in </p> <p class="MsoNormal"><span style="font-style: italic;">D:\bea10\user_projects\domains\blazeds\servers\AdminServer\logs</span> folder and it is called <span style="font-style: italic;">blazeds.log</span>. I could not find any errors in the log, which is a good sign. </p> <p class="MsoNormal"><o:p></o:p>Now the BlazeDS is ready. Open examples URL: <a href="http://localhost:7001/samples/">http://localhost:7001/samples/</a>. You should see a page</p> <a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_ZC88Bkj8_e0/R7Yn7k6QfzI/AAAAAAAAAAk/zpganrW7qPk/s1600-h/Samples1.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_ZC88Bkj8_e0/R7Yn7k6QfzI/AAAAAAAAAAk/zpganrW7qPk/s400/Samples1.png" alt="" id="BLOGGER_PHOTO_ID_5167361526928015154" border="0" /></a> <p class="MsoNormal">The BlazeDS samples use the database that is provided in the BlazeDS distribution. To start the database, open a command prompt window, navigate to <span style="font-style: italic;">\blazeds_b1_020108\sampledb</span> folder and run <span style="font-style: italic;">startdb.bat</span>:</p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_ZC88Bkj8_e0/R7YoMk6Qf0I/AAAAAAAAAAs/_7gasKxqm50/s1600-h/Samples2.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_ZC88Bkj8_e0/R7YoMk6Qf0I/AAAAAAAAAAs/_7gasKxqm50/s400/Samples2.png" alt="" id="BLOGGER_PHOTO_ID_5167361818985791298" border="0" /></a> <p class="MsoNormal">Now lets test drive the BlazeDS. Navigate to the <st1:street st="on"><st1:address st="on">BlazeDS Test Drive</st1:address></st1:street> page<span style=""> </span></p> <p class="MsoNormal"><a href="http://localhost:7001/samples/testdrive.htm">http://localhost:7001/samples/testdrive.htm</a> and follow the sample instructions. All sample applications worked nicely in my case. I’ve got data via HTTPService, Web Services, Java Remoting<span style=""> </span>mechanism just fine.</p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_ZC88Bkj8_e0/R7Yoa06Qf1I/AAAAAAAAAA0/GFsXQE1pCsA/s1600-h/Samples3.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_ZC88Bkj8_e0/R7Yoa06Qf1I/AAAAAAAAAA0/GFsXQE1pCsA/s400/Samples3.png" alt="" id="BLOGGER_PHOTO_ID_5167362063798927186" border="0" /></a>I verified blazeds.log and AdminServer.log files for errors and could not find any. Everything run just fine.<o:p></o:p><p class="MsoNormal"><o:p></o:p>I hope you found this post helpful. Please submit any comments or questions. I will be glad to help.</p><br /><br /><script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script>Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com3tag:blogger.com,1999:blog-7082684402140657004.post-61785036983502758722007-11-18T00:44:00.000-08:002008-02-18T22:18:23.896-08:00MySQL macport install on Mac OS X TigerI have installed mysql5 macport on the MacBookPro laptop running OS X Tiger 10.4.<br /><br />There are a few steps that needs to be done once the port is installed. These steps are not documented (see <a href="http://trac.macports.org/projects/macports/ticket/12694">Ticket #12694</a> on macports.org). So, after reading a few blogs and analyzing mysql startup error messages, I figured out what needs to be done in order to get it running. That info might be useful to others, so I’ve decided to publish the solution here.<br /><br />First of all, we need to create the initial database database<br /><pre><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >$ sudo /opt/local/lib/mysql5/bin/mysql_install_db --user=mysql</span><br /></pre><br />Here is the output of the command:<br /><pre><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" ><br />$ sudo ./mysql_install_db --user=mysql</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >Installing MySQL system tables...</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >071118 0:06:29 [Warning] Setting lower_case_table_names=2 because file system for /opt/local/var/db/mysql5/ is case insensitive</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >OK</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >Filling help tables...</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >071118 0:06:29 [Warning] Setting lower_case_table_names=2 because file system for /opt/local/var/db/mysql5/ is case insensitive</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >OK</span><br /><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >To start mysqld at boot time you have to copy</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >support-files/mysql.server to the right place for your system</span><br /><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >To do so, start the server, then issue the following commands:</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >/opt/local/lib/mysql5/bin/mysqladmin -u root password 'new-password'</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >/opt/local/lib/mysql5/bin/mysqladmin -u root -h my-computer.local password 'new-password'</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >See the manual for more instructions.</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >You can start the MySQL daemon with:</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >cd /opt/local ; /opt/local/lib/mysql5/bin/mysqld_safe &</span><br /><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >You can test the MySQL daemon with mysql-test-run.pl</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >cd mysql-test ; perl mysql-test-run.pl</span><br /><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >Please report any problems with the /opt/local/lib/mysql5/bin/mysqlbug script!</span><br /><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >The latest information about MySQL is available on the web at</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >http://www.mysql.com</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >Support MySQL by buying support/licenses at http://shop.mysql.com</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" ></span><br /></pre><br />Next, I’ve tried to start the database and got this error message:<br /><pre><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >$ sudo /opt/local/lib/mysql5/bin/mysqld_safe </span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >mkdir: /opt/local/var/run: No such file or directory</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >chown: /opt/local/var/run/mysql5: No such file or directory</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >chmod: /opt/local/var/run/mysql5: No such file or directory</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >Starting mysqld daemon with databases from /opt/local/var/db/mysql5</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >STOPPING server from pid file /opt/local/var/db/mysql5/mykola-dzyubas-computer-2.local.pid</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >071118 00:27:12 mysqld ended</span><br /></pre><br />I’ve created /opt/local/var/run and /opt/local/var/run/mysql5 folders:<br /><pre><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >sudo mkdir /opt/local/var/run</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >sudo chmod g+w /opt/local/var/run</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >sudo mkdir /opt/local/var/run/mysql5</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >sudo chown mysql /opt/local/var/run/mysql5</span><br /></pre><br />Once it is done, the mysql server has started successfully<br /><pre><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >$ sudo /opt/local/lib/mysql5/bin/mysqld_safe &</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >Starting mysqld daemon with databases from /opt/local/var/db/mysql5</span><br /></pre><br />Here is a quick check that the database server is up:<br /><pre><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >$ mysqladmin5 -u root -p ping</span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >Enter password: </span><br /><span style="color: rgb(0, 0, 102);font-family:courier new;" >mysqld is alive<br /></span><br /></pre>In case you don't have mysql binary files in your path, please edit ~/.profile and add /opt/local/bin to the path:<br /><br /><span style="font-family: courier new; color: rgb(0, 0, 102);"># Setting the path for MacPorts.</span><br /><span style="font-family: courier new; color: rgb(0, 0, 102);">export PATH=/opt/local/bin:/opt/local/sbin:$PATH</span><br /><br />By default all scripts refer to mysql command, however the installation package creates mysql5. To fix that, create mysql symbolic link that points to mysql5. <br /><br />$ cd /opt/local/bin<br />$ ln -s mysql5 mysql<br /><br />To improve security of the mysql server configuration, please run mysql_secure_installation5 script and configure mysql password for root, network access, etc:<br /><br /><pre><br /><span style="font-family: courier new; color: rgb(0, 0, 102);"><br /><br />$ cd /opt/local/bin<br />$ ./mysql_secure_installation5<br /><br />mykola-dzyubas-computer-2:/opt/local/bin mykola$ ./mysql_secure_installation5<br /><br /><br /><br /><br />NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL<br /> SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!<br /><br /><br />In order to log into MySQL to secure it, we'll need the current<br />password for the root user. If you've just installed MySQL, and<br />you haven't set the root password yet, the password will be blank,<br />so you should just press enter here.<br /><br />Enter current password for root (enter for none): <br />OK, successfully used password, moving on...<br /><br />Setting the root password ensures that nobody can log into the MySQL<br />root user without the proper authorisation.<br /><br />Set root password? [Y/n] y<br />New password: <br />Re-enter new password: <br />Password updated successfully!<br />Reloading privilege tables..<br /> ... Success!<br /><br /><br />By default, a MySQL installation has an anonymous user, allowing anyone<br />to log into MySQL without having to have a user account created for<br />them. This is intended only for testing, and to make the installation<br />go a bit smoother. You should remove them before moving into a<br />production environment.<br /><br />Remove anonymous users? [Y/n] <br /> ... Success!<br /><br />Normally, root should only be allowed to connect from 'localhost'. This<br />ensures that someone cannot guess at the root password from the network.<br /><br />Disallow root login remotely? [Y/n] <br /> ... Success!<br /><br />By default, MySQL comes with a database named 'test' that anyone can<br />access. This is also intended only for testing, and should be removed<br />before moving into a production environment.<br /><br />Remove test database and access to it? [Y/n] n<br /> ... skipping.<br /><br />Reloading the privilege tables will ensure that all changes made so far<br />will take effect immediately.<br /><br />Reload privilege tables now? [Y/n] <br /> ... Success!<br /><br />Cleaning up...<br /><br /><br /><br />All done! If you've completed all of the above steps, your MySQL<br />installation should now be secure.<br /><br />Thanks for using MySQL!<br /><br /></span><br /></pre>Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com4tag:blogger.com,1999:blog-7082684402140657004.post-36312825728419029002007-11-01T22:10:00.000-07:002008-02-18T22:17:53.543-08:00How To Run Java EE 5 Tutorial Examples On MacI spent some time configuring Java environment on Mac. Here are a few tips on how to get it going.<br /><br />The Max OS X comes with Java 5 installed. So, here are main steps:<br /><br />* Download Java EE 5 Tutorial package from <a href="http://java.sun.com/javaee/5/docs/tutorial/information/download.html">http://java.sun.com/javaee/5/docs/tutorial/information/download.html</a><br /><br />* Download Sun Java System Application Server 9.1 from <a href="http://java.sun.com/javaee/downloads/">http://java.sun.com/javaee/downloads/</a>. I downloaded Java EE 5 SDK Update 3 that comes with the application server.<br /><br />* Use instructions posted here on how to install it<br /><br /><a href="http://java.sun.com/javaee/sdk/javaee5sdk_install.jsp">http://java.sun.com/javaee/sdk/javaee5sdk_install.jsp</a><br /><br />Also use Application Server Installation Tips posted here: http://java.sun.com/javaee/5/docs/tutorial/doc/gexaj.html<br /><br />Once the application server is installed, change permissions on the SDK/javadb, so the folder permissions allow creating a database. Here is an example on how to do that:<br /><br /><pre><br />cd SDK <br />sudo chown –R your_name javadb<br /></pre><br /><br />In general, I believe it is a good idea to change permissions to other files in SDK to some less privileged user than root.<br /><br />Once I started playing with bookstore example, I’ve got some build and deployment errors. I found that I need to create a password file and point to it with the javaee.server.passwordfile property. <br /><br />Create a new file app-server-psw.properties in the javaeetutorial5/examples/bp-project/ folder. Edit the file and add <br /><br /><pre><br />AS_ADMIN_PASSWORD=admin_password<br /></pre><br /><br />The admin_password should be the same as it was specified during the Application Server installation.<br />Update javaeetutorial5/examples/bp-project/app-server.properties by adding these properties:<br /><br /><pre><br />db.vendor=javadb<br />javaee.tutorial.home=/Users/mykola/java/j2ee/javaeetutorial5<br />javaee.server.passwordfile=${javaee.tutorial.home}/examples/bp-project/app-server-psw.properties<br /></pre><br /><br />Once that is done, the bookstore example build and deployment works fine.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-85671854987581087902007-10-27T12:37:00.000-07:002007-10-27T12:41:03.886-07:00Java Unboxing and NullWhile playing with boxing/unboxing in Java 5, I found an interesting case. If my collection has a null value, the unboxing fails with a NullPointerException at runtime. Here is an example<br /><br /><pre><br /> Set<Integer> s = new HashSet<Integer>();<br /> for (int i=0; i < 10; i++) {<br /> s.add(i);<br /> }<br /> s.add(null);<br /> <br /> System.out.println("s: " + s);<br /> // this is a problem. The unboxing does not handle null<br /> for (int sx : s) {<br /> System.out.println("sx: " + sx);<br /> }<br /><br /></pre><br /><br />The output of the progam is here:<br /><br /><pre><br />s: [2, 4, null, 9, 8, 6, 1, 3, 7, 5, 0]<br />sx: 2<br />sx: 4<br />Exception in thread "main" java.lang.NullPointerException<br /> at com.mykola.TestSets.main(TestSets.java:21)<br /></pre><br /><br />So, unboxing is fine, unless a collection has a null element.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-48915449831338695142007-08-17T15:06:00.000-07:002007-08-17T15:13:23.206-07:00Macrodef makes Ant strongerI found new macrodef feature in ant extremely useful in my code development. It allows me to reuse lots of code and save time. Here is a quick example on how to use macrodef and why it is cool <br /><br />Let’s say I have several web applications that I need to deploy on the same web server. If I use a regular Ant task, I would have to replicate these lines of code for every application:<br /><br /><code><pre><br /><wldeploy action="deploy"<br /> verbose="${verbose}"<br /> debug="${debug}"<br /> name="myApp"<br /> source="${output.dir}/myApp.war"<br /> user="${admin.username}"<br /> password="${admin.password}"<br /> adminurl="${adminurl}"<br /> targets="myWebSiteDomain" /><br /></pre></code><br /><br />I know it does not look that bad, but this is just a short sample. In a real world case, I also need to compile the application, generate a WAR file, deploy it, generate a client stub, etc. So, the Ant build.xml tends to grow very fast. In one of my previous project with about #5,000 the build.xml was over 700 lines of code. <br /><br />Here is a solution that I like. I define a macro that deploys my application:<br /><br /><code><pre><br /><macrodef name="myApp.deploy"><br /> <attribute name="name" /><br /> <sequential><br /> <wldeploy action="deploy"<br /> verbose="${verbose}"<br /> debug="${debug}"<br /> name="@{name}"<br /> source="${output.dir}/@{name}.war"<br /> user="${admin.username}"<br /> password="${admin.password}"<br /> adminurl="${adminurl}"<br /> targets=" myWebSiteDomain " /><br /> </sequential><br /></macrodef><br /></pre></code><br /><br />Once it is defined, I can deploy a set of applications simply by calling:<br /><br /><code><pre><br /><myApp.deploy name="myApp1" /><br /><myApp.deploy name="myApp2" /><br />…<br /><myApp.deploy name="myAppN" /><br /></pre></code><br /><br />The macro above can be enhanced to do other tasks. I find it very convenient. I think it is a good practice to replace lots of repetitive tasks in Ant build file with a macro.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-32906455614161768192007-08-10T14:48:00.000-07:002007-08-10T14:51:54.078-07:00Some Perforce TipsHere is a small one line command that I created to find all local files, i.e. the files that still need to be added to the repository:<br /><br /><pre><code><br />find . -type f -print | xargs p4 filelog -m 1 | grep "not on client"<br /></code></pre><br /><br />I like to work with svn more. The "svn status" makes the same thing much more easier.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-82429087886588952302007-07-05T15:06:00.000-07:002007-07-05T15:09:41.945-07:00Weblogic 10.0 ClasspathThe classpath in Weblogic 10.0 has changed comparing to 9.2 version. Here is what I have in my build.xml now. It works for a simple web service and Weblogic tools such as jwsc, clientgen, wldeploy.<br /><br /><pre><br /> <path id="wl.class.path"><br /> <pathelement location="${wl.home}/jrockit_150_08/lib/tools.jar" /><br /> <pathelement location="${wl.home}/patch_wls1000/profiles/default/sys_manifest_classpath/weblogic_patch.jar" /><br /> <fileset dir="${wl.home}/wlserver_10.0/server/lib"><br /> <include name="weblogic_sp.jar" /><br /> <include name="weblogic.jar" /><br /> <include name="webservices.jar" /><br /> <include name="xqrl.jar" /><br /> </fileset><br /> <fileset dir="${wl.home}/modules/features"><br /> <include name="features/weblogic.server.modules_10.2.0.0.jar" /><br /> <include name="features/com.bea.cie.common-plugin.launch_2.2.0.0.jar" /><br /> <include name="org.apache.ant_1.6.5/lib/ant-all.jar" /><br /> <include name="net.sf.antcontrib_1.0b2.0/lib/ant-contrib.jar" /><br /> </fileset><br /> </path><br /></pre><br /><br />The wl.home is set to d:/bea10 in my case. It is a pointer to a folder where Weblogic is installed.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-57759591228178399872007-07-05T14:45:00.001-07:002007-07-05T15:05:01.267-07:00How to post a code snippet here?I have a few lines of code that I want to post here. The cut and paste does not work. Here is a simple solution I found in posts on groups.google.com. The idea is to replace < and > with & lt;, & gt; symbols. Here is how it looks like:<br /><br /><pre><br /> <tag>value<tag><br /></pre>Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0tag:blogger.com,1999:blog-7082684402140657004.post-23910407217907358032007-06-13T00:17:00.000-07:002007-06-13T00:23:29.707-07:00Why Blog?I always keep notes when I am working on a project or study. I found it very useful. I write some tips on how to do something. I write some ideas. I use my notes a lot. So, I thought maybe I should share my notes with others and maybe it will be helpful to them too. Here you go. This blog is for me and everybody who might find it useful.Mykolahttp://www.blogger.com/profile/18386705498629883185noreply@blogger.com0