tag:blogger.com,1999:blog-66973730818136024022024-02-20T06:07:23.938-08:00Smart Software Factory Tech BlogSmart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.comBlogger28125tag:blogger.com,1999:blog-6697373081813602402.post-35524706803729126102014-02-20T15:43:00.000-08:002014-02-20T15:43:06.433-08:00Solving problems when installing Jasperserver in Centos 6.xWhen you try to install jasperserver in Centos 6.x you can face errors like:<br />
<br />
<code>
Warning: Problem running post-install step. Installation may not complete<br />
correctly<br />
Error running<br />
/usr/jasperserver/jasperreports-server-cp-5.5.0/apache-ant/bin/ant<br />
import-minimal-ce :<br />
BUILD FAILED<br />
/usr/jasperserver/jasperreports-server-cp-5.5.0/buildomatic/bin/import-export.xml<br />
:275: The following error occurred while executing this line:<br />
/usr/jasperserver/jasperreports-server-cp-5.5.0/buildomatic/bin/import-export.xml<br />
:158: Java returned: 255<br />
</code>
<br />
<div>
<br />
<br />
At least in our installation the problem was that the "<b>myservername</b>.localdomain" wasn't included in the file /etc/hosts.<br />
<br />
It should look like this:<br />
<br />
127.0.0.1 localhost <b>myservername</b>.localdomain<br />
<br />
I hope this can help someone.</div>
Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com1tag:blogger.com,1999:blog-6697373081813602402.post-41806547568782362782013-02-18T20:58:00.001-08:002013-02-18T20:58:28.305-08:00Deploying JasperServer on Glassfish V2 finalAfter following the JasperServer installation guide step by step in order to deploy the JasperServer.war in an existing Glassfish V2 installation I got this exception when trying to start the app server:<br />
<br />
<code>java.lang.IllegalAccessException: Class com.sun.jersey.core.spi.component.ComponentConstructor can not access a member of class com.sun.jersey.json.impl.provider.entity.JSONArrayProvider with modifiers ""<br />
</code>
<br />
<br />
It looks like there's a a conflicting jakson-jersey libs by default in glassfish V2 final. To correct the problem you must download Jerseys libs and replace the ones in [glassfish-folder]/lib.
Specifically the bad libs are: <br />
<code><br />jackson-asl-0.9.4.jar<br />
jersey-bundle-1.0.3.1.jar<br />
jettison-1.0.1.jar</code><br />
<code><br /></code>
<code>You can find the non conflicting libs here:</code><br />
<code><br />
<a href="http://maven.java.net/service/local/artifact/maven/redirect?r=releases&g=com.sun.jersey&a=jersey-archive&v=1.12&e=zip">http://maven.java.net/service/local/artifact/maven/redirect?r=releases&g=com.sun.jersey&a=jersey-archive&v=1.12&e=zip</a></code>Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-14998940579956212892012-05-11T23:12:00.000-07:002012-05-11T23:14:08.672-07:00Warning!!!! Thread.sleep called in loopWow serveral months since last post!
<br/>
<br/>
Well returning to the topic, when you write a code block like this:
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEw6K_RFNq49nnWI2Hnn_puWEIdjpRoZTnXT4RHuCd2vlfZKlRKQUIfCQbc5sZOem73j3idYLqkvKJ9z3bFsruJmeAfyUgBkmPilj_31LUn45eR3INJV4dZL-A2GBG9fwzdohElb3mXU9m/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> while(timeout()){
try{
Thread.sleep(1);
}catch(Exception e){}
}
</code></pre>
Some IDEs as Netbeans or some software quality tools popup a warning informing that this kind of code usually is a design flaw or a bad practice, in other words a code smell. If you search in google you will get quick answers like "if you put a Thread.sleep inside a loop you are writting inneficient code, you should use notify and wait" but at the end of the day I have never found a clear example of how this code conversion from a "while" loop to a monitored code should be done.
So.... here's the example, lets think an hipotetical problem where one thread is pooling a message bus. If you send a message trough the message bus you must wait an amount of time for another message that is a response for the sent message. The amateur way of implementing this would look like:
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEw6K_RFNq49nnWI2Hnn_puWEIdjpRoZTnXT4RHuCd2vlfZKlRKQUIfCQbc5sZOem73j3idYLqkvKJ9z3bFsruJmeAfyUgBkmPilj_31LUn45eR3INJV4dZL-A2GBG9fwzdohElb3mXU9m/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> Message lastMessage = null;
void sendMessage(Message messageToSend){
messageToSend.send();
while(!timeout()){
if(lastMessage != null){
reponseReceived(lastMessage);
lastMessage = null;
}
try{Thread.sleep(sleepTime);}catch(Exception e){}
}
}
//The message bus listener code, this is not that relevant
//We can just assume that this method is called from other thread.
void messageFoundInBus(Message responseMessage){
lastMessage = responseMessage;
}
</code></pre>
This code works but have two main problems. First, this is not efficient because sleepTime will put the Thread to sleep for a fixed amount of time. E.g. If you have 10 seconds in this constant the worst scenario is receiving the Message just after start sleeping making the Thread wait 9.x seconds to be aware of the response even if the message arrived long time ago. You could say, just use a smaller value but that could cause a different problem because if the sleep time is to short or you even decide to not put the Thread.sleep you could face starvation.
The second problem is that while you are sleeping you could get a second message and override your response. There's no locking code. You could just include some synchronized sentences but you could forget it just because you are not forced to synchronize anything. If you use notify and wait you will be forced to synchronize this code avoiding this kind of problems from the beggining.
Here's a second aproach using notify and synchronize:
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEw6K_RFNq49nnWI2Hnn_puWEIdjpRoZTnXT4RHuCd2vlfZKlRKQUIfCQbc5sZOem73j3idYLqkvKJ9z3bFsruJmeAfyUgBkmPilj_31LUn45eR3INJV4dZL-A2GBG9fwzdohElb3mXU9m/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> Message lastMessage = null;
final Object responseMonitor = new Object();
void sendMessage(Message messageToSend){
try{
messageToSend.send();
if(lastMessage != null){
synchronized (responseMonitor) {
responseMonitor.wait(timeout);
}
}
if(lastMessage != null){
reponseReceived(lastMessage);
lastMessage = null;
}
}catch(Exception e){}
}
//The message bus listener code, this is not that relevant
//We can just assume that this method is called from other thread.
Message lastMessage = null;
void messageFoundInBus(Message responseMessage){
synchronized (responseMonitor) {
lastMessage = responseMessage;
responseMonitor.notify()
}
}
</code></pre>
The solution that I present is not an absolute rule, there are a lot of reasons not related to wait for a resource that could bring you to need a loop with a sleep inside, but almost every time you should be able to find a better way in order to avoid this kind of code.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com1tag:blogger.com,1999:blog-6697373081813602402.post-80282842542980681582011-07-31T22:08:00.000-07:002011-07-31T22:08:58.310-07:00Moving files to honeycomp tablet internall memory using linux (without pain)Long time since my last post but I have been a little busy! I got really frustrated trying to send some files to my asus transformer this weekend (using ubuntu). I tried to mount it as a file system via mtp but it was a complete failure, slow transfer rate, corrupted transfers, tablet frezzes, etc, etc, are some of the main problems that I faced.<br />
<br />
I was almost done when I decided to try another aproach, I decided to install a SSH server in my laptop and a FTPs client in the tablet. The result? Flawless victory. Yes the transfer rate will never be as USB but is really convenient downloading my movies directly from my bed. :)<br />
<br />
To install the SSH server in linux (at least if you are using any debian based distribution) just type:<br />
<br />
sudo apt-get install ssh<br />
<br />
And the scp client of my choise was AndFTP that can be found in the android market.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-23657835743327819462011-01-30T18:11:00.000-08:002011-01-30T19:34:41.573-08:00Fix TV overscan using ubuntu nvidia privative driversI have an old LG HD-TV and I have been struggling trying to make it work fine with my ASUS laptop. The problem is that when I start "twin view" using the HDMI output of the laptop I get overscan in the TV, this means that I can't see my full desktop because 200 pixels in X axis and Y axis are lost. I have read in a lot of forums that modifing the device ID using a binary file or modifying directly the xorg.conf are the only workarounds to solve this problem but after spending almost an hour I discovered that nvidia-settings have its own tool to fix overscan.<br />
<br />
I'm using 260.19.06 version installed using the official ubuntu repositories. To change the overscan simply launch nvidia-settings and go to Xserver Display Configuration. Detect your tv and enable it in twin view or as main screen. Now in the nvidia-settings main menu select your GPU tab and search your TV, in my case it says DFP-1 (LG Electronics 32LCD2D-MD). Select it and if you don't see a scroll-bar with title "Oversan Compensation" then click "ResetDefaults" button. After that operation you should see the "Oversan Compensation" scrollbar and you can scale the output to fit your TV size.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMY_HMNBU-u9TFcBY5v7ZKRhRU8PWxFsViwTWN8NwbnRuF7aRz90e4AZ0jiiuo7KMtYEUYniJCDW3S_EO125gE0V2sWzNDn9KlndNZw58JHxKyCV-muPo07ANSBltTYCPfszzne6VE0AE/s1600/Pantallazo.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="95" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMY_HMNBU-u9TFcBY5v7ZKRhRU8PWxFsViwTWN8NwbnRuF7aRz90e4AZ0jiiuo7KMtYEUYniJCDW3S_EO125gE0V2sWzNDn9KlndNZw58JHxKyCV-muPo07ANSBltTYCPfszzne6VE0AE/s400/Pantallazo.png" /></a></div><br />
<br />
This driver have a lot of glitches and bugs, for example when I change any configuration I can't see the "accept configuration dialog" so I need to guees where is the accept button. In a similar way every time I change any configuration I lost my system theme and get reverted to gnome default theme. Those problems didn't presented when I was using the official drivers downloaded directly from Nvidia but after the last kernel update I just can't figure out how to make them work again. :(Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-60074451257302245802011-01-21T23:29:00.000-08:002011-01-23T22:36:32.782-08:00Mantain more than one music library in RhythmboxThis is a really strange requirement but there are sometimes that you may want to mantain two separate libraries using the same linux user. In my case, I have one library in /home/myUser/Music and other one in /home/myUser/MusicLowQuality. This is usefull because I mantain a second version of all my music in a lower quality for syncing my mp3 player. The problem starts when you import this two folders to Rhythmbox because you will have a duplicate of every single song.<br />
<br />
The Rhythmbox Library Database is stored in ~/.local/share/ryhtmbox/rythmdb.xml by default but you can invoke rythmbox this way to take any file you want:<br />
<br />
<code><br />
rhythmbox --rhythmdb-file=/home/myuser/.local/share/rhythmbox/mynewdb.xml<br />
</code><br />
<br />
This way you can create two diferent launchers that target to two different music libs. This is terrific but I found just one annoying behaivior. If you have the auto-inspect option enabled pointing to /home/myUser/Music and invoke the launcher that use the LowQuality folder when you include new music files to /Music they will be included in the wrong lib. This is a little difficult to explain :3<br />
<br />
The easiest solution that I found was changing the path to the inpection folder before calling the launcher.<br />
<br />
you can invoke rythmbox this way to take any file you want:<br />
<br />
<code><br />
gconftool -s /apps/rhythmbox/library_locations -t list --list-type string [file:///home/myUser/MusicLowQuality] && rhythmbox --rhythmdb-file=/home/myuser/.local/share/rhythmbox/lowqualitydb.xml<br />
<br />
gconftool -s /apps/rhythmbox/library_locations -t list --list-type string [file:///home/myUser/Music] && rhythmbox --rhythmdb-file=/home/myuser/.local/share/rhythmbox/normaldb.xml<br />
</code><br />
<br />
I hope this can be useful for someone :)Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-57292157766893521962011-01-11T20:39:00.000-08:002011-01-11T20:44:45.050-08:00Integrating liquibase in your java codeIn modern software developing, versioning your source code is a most do and you can easilly find robust opensource and privative solutions to mantain a healthy versioned code. In the other hand, most developers agreed that versioning the changes made in your data model is as important than versioning your source code, but the tools available to do this task are not as extended and documented as the first ones.<br /><br />In most projects that I have had the opportunity to participate the usual way to version the database is creating SQL scripts and run them in a progresive way. This does the job but have some drawbacks, for example:<br /><br />1 If you use an ORM for the persistence of your project then you must write the versioning scripts for all the different database providers that you want to support.<br />2 If you need rollback functionallity then you must mantain two scripts.<br />3 If you have different branches in your projects merging changes can be a tiring process.<br />4. You must write plumbing code for versioning in your project. The old reinventing the wheel problem.<br /><br />We decided to try Liquibase, an interesting database versioning tool that solves most the problems presented, mantaining the changes of your database in an "engine independent" way and supports rollbacks, diffs and tagging. We are not explaining how to use this tool here because the official documentation that you can find in liquibase.com is really good, what we will be explaining here is something that we couldn't find in the official documentation and this is including the liquibase library directly in you java code and use this as an API.<br /><br />Liquibase was intended to be used via command line, ANT scripts and maven. In our case this wasn't enough and we wanted to be able the call and use the liquibase services directly in our java code to have the flexibility to do runtime updates in our own project. We tried to access directly the Liquibase object with no luck, we experimented many exceptions and hard times because the source code of liquibase is not documented as we would like, so the final desition was using the command line integration class.<br /><br />First you need to download liquibase 2.0 and the jdbc connector for your database and include them in your project libraries. Next you need to extend from the class liquibase.integration.commandLine.Main (yes this is really ugly, we will still searching a better way).<br /><br /><code><br /><br />public class DatabaseVersioningService extends liquibase.integration.commandline.Main implements DatabaseVersioningServiceLocal {<br /> private static final String DATABASENAME_CHANGELOG_PARAM = "DATABASENAME";<br /> private static final String CHANGELOG_PATH = "changeLogs/changelog_master.xml";<br /> private static final String MYSQL_CLASS_DRIVER = "com.mysql.jdbc.Driver";<br /> private static final String UPDATE_COMMAND = "update";<br /><br /> public void updateToHEAD(String dbUser, String dbPassword) {<br /> try {<br /> setMigrationParameters(dbUser, dbPassword);<br /> applyDefaults();<br /> configureClassLoader();<br /> doMigration();<br /> } catch (Throwable ex) {<br /> ex.printStackTrace();<br /> }<br /> }<br /><br /> private void setMigrationParameters(String dbUser, String dbPassword, String command) throws URISyntaxException, SQLException {<br /> changeLogFile = getClass().getResource(CHANGELOG_PATH).getPath();<br /> username = dbUser;<br /> password = dbPassword;<br /> driver = MYSQL_CLASS_DRIVER;<br /> url = new URI(padposDataSource.getConnection().getMetaData().getURL());<br /> command = command;<br /> }<br />}<br /><br /></code><br /><br />Like you can see in the sample code is really simple but figure out this from the liquibase source code wasn't that easy, so we hope this can help someone else that wants to integrate liquibase directly in code. We will be studying liquibase code and maybe we will be writting a service tier to make this in a cleaner and elgant way.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-5677117587240724082011-01-02T22:56:00.000-08:002011-01-02T23:09:07.213-08:00JDownloader, better ubuntu integrationWell... this is a really dumb post but I just discover this a few minutes ago and maybe can help someone else. If you are running jdownloader in ubuntu or any gnome linux platform maybe you noticed that by default the theme is java metal. I don't dislike the theme but this have some issues with compiz, for example sticky windows simply doesn't work and sometimes you can't maximize. In the other hand always is nice having an unified look and feel for all apps.<br /><br />You can open JDownloader, open preferences tab and select interface node. In theme option you should select "Light(GTK)" and restart JDownloader. That's it now JDownloder behavior and "look and feel" is just like any other Gnome app.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-31861076623297502772010-12-08T21:04:00.000-08:002010-12-22T20:25:09.503-08:00Offline maps on android! Atlas Creator and rmap the perfect dumbbell.I bought a Samsung Galaxy Tab some weeks ago :) but I haven't adquired a 3G plan. This prevents me to use Google Maps and use my device build in GPS capabilities. After some research I found in android market an application called rmap that simply rocks!. You can create your own maps upload them and enjoy.<br /><br />The problem is, where to obtain this maps? Well there's a desktop application (written in java of course :) ), that creates a multilayer map based in a great huge variety of map engines like google maps (my favorite), bing, yahoo, etc., and can export portions of the map to many diferent file types.<br /><br />The big problem (not that big) is that rmaps uses an output map format called "BigPlanet SQLLite" that is not supported by default in Atlas Creator. This can be fixed quickly following the next steps in Ubuntu 10.10:<br /><br />1. Download Atlas Creator from http://mobac.dnsalias.org/ (I'm using version 1.7 but the latest stable version is 1.8, desicion up to you)<br />2. Download SqlLite Libs from http://www.datafilehost.com/download-909a5d21.html. (I used ubuntu 9.10 x64 but this is dependant of your cpu)<br />3. Download SqlLite.jar from http://www.ch-werner.de/javasqlite/javasqlite-20100727-win32.zip (yes! is a windows build but don't worry remember that java is multiplatform)<br />4. Copy libsqlite_jni.so and sqlite.jar to 3-Mobile Atlas Creator 1.7 folder. (In the same place that you can fin start.sh)<br />5. Run Mobile_Atlas_Creator.jar (java -jar Mobile_Atlas_Creator.jar)<br /><br />Now you can select the area that you expect to use offline (for example your entire city or your next vacation destiny) and select the zoom level that you want to be available. (WARNING selecting level 18 and 19 will produce big map databases, personally I use from zoom 1 to 17). Finally, don't forget to select "BigPlanet SQLLite" format, name your atlas and sections and run "Create Atlas".<br /><br />After some minutes depending in the area selected you will have a map file in /home/atlases/ that you need to copy to your android mobile device in the path /rmaps/maps/.<br /><br />This way you will have a Google Map (or any provider map) completly offline and functional!Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-70129847866348608662010-12-07T13:16:00.000-08:002010-12-07T13:37:29.504-08:00Hide Glassfish behind an Apache server. Avoid typing server port and application name!When you deploy a WebModule in Galssfish you can access the application using an URL like:<div><br /></div><div>http://mydomain.com:GlassfishServerPort/MyWebApp-war</div><div><br /></div><div>Typing the port of the glassfish domain and WebApp name can be really annoying. You can follow the next steps to create an aliase subdomain to access in an easier way your application.</div><div><br /></div><div>First of all you need to configure your subdomains contacting your DNS provider. This is the only step I can't explain in detail because is very dependant of your DNS provider. In this example we will be using the subdomain "subdomain".</div><div><br /></div><div><code></div><div>subdomain.mydomain.com</div><div></code></div><div><br /></div><div>If your DNS is correctly configured you should be able to ping this URL and get response.</div><div><br /></div><div>The next step is configuring a Virtual Host in APACHE for this subdomain.</div><div><br /></div><div><div>-Go to /etc/httpd/conf/httpd.conf (Or any place where you have the global APACHE configuration file)</div><div>-Go to last line and write:</div><div><br /></div><div><code></div><div><div><VirtualHost *:80></div><div>ServerName subdomain.mydomain.com</div><div>ProxyPass / http://subdomain.mydomain.com:GlassfishServerPort/</div><div>ProxyPassReverse / http://subdomain.mydomain.com:GlassfishServerPort/</div><div></VirtualHost></div></div></div><div></code></div><div><br /></div><div>After restarting HTTPD service you should be able to navigate to subdomain.mydomain.com and get the Glassfish welcome page. This is good but, it would be better an instant redirection to our app. To achive this you need to execute this command in your glassfish domain to asign the defaul app for the server:</div><div><br /></div><div><code></div><div>asadmin set server.http-service.virtual-server.server.default-web-module=MyWebApp-war#MyWebApp-war.war</div><div></code></div><div><br /></div><div>You can even configure this usign the web admin console. (Configuration->HTTP Service->Virtual Servers).</div><div><br /></div><div>That's it, now you have a cleaner an easier way to access your app, and your clients will be really thankfull.</div>Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-57886104099664711542010-11-04T22:33:00.000-07:002010-11-04T23:11:11.993-07:00Move items from one listbox to another listbox without pain in C#I blamed Java Swing more than once for the lack of rich controls for my GUIs but the Microsoft world is not an exception to the rule. In most application I have written in .Net, I required a component for asign and deallocate objects and I'm sure I'm not the only one human being with this need, sadly there's no official control that provides this functionality (or at least I haven't found it).<br /><br />My solution was use two ListBoxes (one for the asigned items and one for the deallocated items) and put some buttons between them, you know the classic asign all, asign selection, deallocate all and finally deallocate all. To avoid writing multiple times the same move item code I created two gold rules to operate my list boxes:<br /><br />1. You have to provide the items to the ListBoxes binding a generic List.<br />2. The items should be objects with a correct overriden Equals method.<br /><br />The mandatory screenshot:<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtEWliQJdgGLJu1CTtX3G_Q3m-V5UyGvU4CdFUvFWn6MdZR77hpZXYUuqBLtZs4lXdOub_ajQy0ZAJIutjqKWGlQ9mHl9sez9iNyQ7M2k1p9dfRvqVZjEYHnyI9dBHDnF9f48SvrhH4gA/s1600/Pantallazo.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 285px; height: 231px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtEWliQJdgGLJu1CTtX3G_Q3m-V5UyGvU4CdFUvFWn6MdZR77hpZXYUuqBLtZs4lXdOub_ajQy0ZAJIutjqKWGlQ9mHl9sez9iNyQ7M2k1p9dfRvqVZjEYHnyI9dBHDnF9f48SvrhH4gA/s400/Pantallazo.png" alt="" id="BLOGGER_PHOTO_ID_5535935731187170130" border="0" /></a><br /><t><br /><br />The events of all buttons:<br /><br /><code><br />private void asignAllButton_Click(object sender, EventArgs e)<br />{<br />moveAllItems(notAsignedListBox,asignedListBox);<br />}<br /><br />private void asignSelectionButton_Click(object sender, EventArgs e)<br />{<br />moveSelectedItems<MyObject>(notAsignedListBox, asignedListBox);<br />}<br /><br />private void deallocateSelectionButton_Click(object sender, EventArgs e)<br />{<br />moveSelectedItems<MyObject>(asignedListBox, notAsignedListBox);<br />}<br /><br />private void deallocateAllButton_Click(object sender, EventArgs e)<br />{<br />moveAllItems<MyObject>(asignedListBox, notAsignedListBox);<br />}<br /></code><br /><br />The utility methods:<br /><br /><code><br />public static void moveSelectedItems<T>(ListBox source, ListBox destiny)<br /> {<br /> var selectedList = source.SelectedItems;<br /> if (selectedList == null || selectedList.Count == 0)<br /> {<br /> return;<br /> }<br /> var destinyList = (List<T>)destiny.DataSource;<br /> var sourceList = (List<T>)source.DataSource;<br /> if (destinyList == null)<br /> {<br /> destinyList = new List<T>();<br /> }<br /> foreach (T generic in selectedList)<br /> {<br /> destinyList.Add(generic);<br /> sourceList.Remove(generic);<br /> }<br /> destiny.DataSource = null;<br /> source.DataSource = null;<br /> destiny.DataSource = destinyList;<br /> source.DataSource = sourceList;<br /> }<br /><br />public static void moveAllItems<T>(ListBox source, ListBox destiny)<br /> {<br /> if (source.DataSource == null)<br /> {<br /> return;<br /> }<br /> var destinyList = (List<T>)destiny.DataSource;<br /> if (destinyList == null)<br /> {<br /> destinyList = new List<T>();<br /> }<br /> destinyList.AddRange((List<T>)source.DataSource);<br /> destiny.DataSource = null;<br /> destiny.DataSource = destinyList;<br /> source.DataSource = null;<br /> }<br /></code><br /><br />Now you have a cross object asignation component. God! My favorite programing language is Java but my blog is being invaded by C# posts ! :S</t>Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-77165830178568035242010-10-31T21:03:00.000-07:002010-10-31T21:07:35.180-07:00Avoid ListView flicker and scrollbar reset when refreshing its itemsIf you need to refresh the data of a listview frequently (every 20 seconds, for example) we don't recommed you use the listview "clear()" method and set again all the items. This approach have two major drawbacks. <br /><br />1. You will be experimenting an annoying flicket every time you call "clear()" method.<br />2. The scrollbars of the listview will be reseted to (0,0) position.<br /><br />To avoid this behaivior we recommed you instead of clearing everything, just add new items and remove the ones that you don't need anymore.<br /><br />Our implementation mantains all the time a second generic list synchronized with the listview, this is a better aproach to us 'cause all the items are obtained from the database and we minimize the number of access to database.<br /><br />First our ListView will be displaying MyObjects:<br /><code><br />public class MyObject : IEquatable<MyObject><br /> {<br /> public int id { get; set; }<br /> public bool Equals(MyObject other)<br /> {<br /> if (Object.ReferenceEquals(other, null)) return false;<br /> if (Object.ReferenceEquals(this, other)) return true;<br /> return id.Equals(other.id);<br /> }<br /> public override int GetHashCode()<br /> {<br /> return id;<br /> }<br /> }<br /></code><br /><br />The code that populates the list and refresh it:<br /><br /><code><br />void refresh(){<br /> //findMyObjects return the new IList<MyObject> that we want to sync<br /> var myObjectsNew = findMyObjects();<br /> var myObjectsToAdd = deleteItemsListView<MyObject>(myObjectsOld,myObjectsNew,listView);<br /> foreach (MyObject myObjectToAdd in myObjectsToAdd)<br /> {<br /> var item = new ListViewItem(myObjectToAdd.id.ToString());<br /> item.Name = myObjectToAdd.id.ToString();<br /> listView.Items.Add(item);<br /> myObjectsOld.Add(myObjectToAdd);<br /> }<br />}<br /></code><br /><br />The delete method (returns the elements to add):<br /><br /><code><br />public static IList<T> deleteItemsListView<T>(IList<T> oldList, IList<T> newList, ListView listView)<br /> {<br /> var intersection = newList.Intersect<T>(oldList);<br /> var itemsToAdd = newList.Except<T>(intersection);<br /> var itemsToRemove = oldList.Except<T>(intersection);<br /> for (int i = itemsToRemove.Count() - 1; i > -1; i--)<br /> {<br /> T objetoParaEliminar = itemsToRemove.ToList()[i];<br /> for (int j = 0; j < listView.Items.Count; j )<br /> {<br /> if (listView.Items[j].Name == objetoParaEliminar.GetHashCode().ToString())<br /> {<br /> listView.Items.RemoveAt(j);<br /> break;<br /> }<br /> }<br /> for (int j = 0; j < oldList.Count; j )<br /> {<br /> if (oldList[j].Equals(objetoParaEliminar))<br /> {<br /> oldList.RemoveAt(j);<br /> break;<br /> }<br /> }<br /> }<br /> return itemsToAdd.ToList<T>();<br /> }<br /> }<br /></code><br /><br />Complex? Yes, a little. It would be terrific having a generic ListViewItem in the ListView with a "sync()" method but thats not the case, another solution could be binding the list to a datasource like this guy in "code project":<br /><br />http://www.codeproject.com/KB/list/ListView_DataBinding.aspx<br /><br />To be honest, his implementation is more elegant but to our purposes this is enough.<br /><br />Important points in our implementation:<br /><br />1. All your items must have a unique id and must implement IEquatiable interface (we are using linq).<br />2. We assume that if the id is already in the list view this is synchronized. This means that we only add and delete new ids but didn't verify if item changed.<br />3. If you reorder in some way the ListView you can't ensure that the generic list can be acceded using the indices of the listview.<br />4. myObjectsOld generic list should be class scoped and should be the same reference to every call to refresh method.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-57418783329003343872010-10-22T23:54:00.000-07:002010-10-23T01:05:40.785-07:00Synchronize folders between two ubuntu terminals automaticallySometimes you want to synchronize the documents of your desktop with the documents in your laptop (you could want to sync all your photos, music or documents), this can be a time consuming task and you can easilly lose changes, duplicate files or simply forget to sync. To avoid this we will explain here how to install a sync folder server in ubuntu, configure it and finally sync automatically every time we start our computer.<br /><br />Before anything we need to install some software in both terminals (in our case the latop and the desktop):<br /><br /><code><br />sudo apt-get install unison-gtk,unison,expect,openssh-server<br /></code><br /><br />Unison is the synchronization server that mantains the differences between local and remote folders, unison-gtk is a graphical interface for unison, expect is a program that allow us write powerfull shell scripts and finally open-ssh is the server that implements the secure shell connections.<br /><br />After installing, we should test the ssh server writing in terminal this command:<br /><br /><code><br />ssh host-address -l user<br /></code><br /><br />Replace host-address with the address of the remote server. This could be an ip.<br />Replace user with your ubuntu user.<br /><br />You should be asked to accept a certificate and after taht you need to input your password.<br /><br />Next, we need to create a profile in unison. To make easier this process, we are going to use unison-gtk. Click the "add profile button" and give it a name like "MyUnisonProfile", next, for the local folder set something like /home/mylocaluser/thelocalfolderToSync, in the next page you must provide the remote folder to sync. This should be something like /home/myremoteuser/myremotefolder, check the SSH option and give the remote server.<br /><br />If you provided correct information you should be prompted to input password, and finally you should see a table with the differences between the two folders. If you click Go button the two folders will be merged and from this point every change made in any folder (remote or local) can be sync using this tool.<br /><br />This is terrific but like we explained in the beggining of the post, we would like to automate this process to ensure that our folders are up to date with no efford. To achive this we are going to write an script that syncs the unison profile "MyUnisonProfile" when we start our gnome session.<br /><br />First of all create a file in your home directory "unisonScript.sh" and paste this code inside replacing the password and the profile with the correct values:<br /><br /><code><br />PROFILE_NAME=MyUnisonProfile<br />SSH_PASSWORD=myremoteuserpassword<br /><br />echo "Waiting for networking"<br />sleep 60;<br />echo "Sync folders"<br />expect -c "set timeout -1;\<br />spawn unison $PROFILE_NAME -batch<br />match_max 100000;\<br />expect *password:*;\<br />send -- $SSH_PASSWORD\r;\<br />interact;"<br />echo "Done"<br /></code><br /><br />You can test this script double-clicking in nautilus and selecting execute on terminal or running in any terminal:<br /><br /><code><br />sh unisonScript.sh<br /></code><br /><br />Note that the script starts but waits 60 seconds before sync, we need to sleep because the network is not ready until some seconds after gnome login. We could not find a better way to wait until networking is ready :(<br /><br />The last step is call this script adding the sh unisonScript.sh line to the end of .bashrc file that can be found in your home directory.<br /><br />WARNING: This script is in batch mode! This means that you won't be asked for any permission. If you delete a file in any terminal, after running this script you will miss this archive in both terminals.<br /><br />PS: If you install unison-gtk using the ubuntu software center, the "unison" command will be linked autommatically to unsion-gtk. This won't allow you to create a completely silent script because this will open the gtk window. In this case you need to look for the command line tool and call this command directly Eg. unison-2.32.52Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-90329756704821057842010-10-22T14:50:00.000-07:002010-10-22T15:15:53.123-07:00Cannot navigate association field [field] in the SET clause target TOPLINKWe migrated an application from Hibernate to TopLink with almost no efford, having an standard pesistence layer is awesome! Anyway some querys after the migration wasn't working and we were getting<br />'cannot navigate association field [field] in the SET clause target exceptions'. This happends because TopLink is a little more strict about your Entity Relations.<br /><br />Example:<br /><br />You have an entity School that includes an entity adress, and in the same way the adress is identified using an integer adressID. <br /><br />School Entity<br /><br /><code><br />@Entity<br />class School{<br />@ID<br />private int schoolID;<br />@OneToOne<br />private Address address;<br />}<br /></code><br /><br /><code><br />@Entity<br />class Address{<br />@ID<br />private int addressID;<br />}<br /></code><br /><br />If you create this query:<br /><br />UPDATE School s SET s.address.adressID = :anAddressID<br /><br />Hibernate will not complain but Toplink will fail. In toplink is mandatory to use the entity object instead the attributes of the entity: The correct query in toplink is:<br /><br />UPDATE School s SET s.address = :anAddress<br /><br />In my opinion is better using the entity object and not the ids 'cause you are taking advantage of the object abstraction provided by the persistence provider.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-12205682932782236892010-10-20T21:37:00.000-07:002010-10-22T15:27:45.427-07:00Bypass the browser sandbox with a Java AppletThis is an aproach we followed some months ago to bypass the browser sandbox and to be honest this solution (for our porpouses) was simply terrific. We want to share it because there's not a lot of documentation in the net about communicating your applet, browser and OS.<br /><br />First a brief about how browsers "sandbox" work. All the browsers (at least the secure ones) have a tier that is called the "sand box", this "sand box" prevents executing harmfull code in a webpage, for example, this denies any operation in ports, hard drive, monitor, sound card, etc. This "sand box" is an important safe in all browsers because no one wants to enter a webpage and allow some nasty code to format our harddrive, but in the same way this limits the posibilities of the developers of writing code that interacts with the hardware of the user.<br /><br />Our requirement was reading a string displayed in a webpage and when the user clicks a button send the string via serial COM. The possible approaches that we figured out are:<br /><br />1. Using an ActiveX Control:<br /><br />Pros: <br /><br />There's already a control that does this work.<br /><br />Cons: <br /><br />This code will work only in Internet Explorer.<br />This is a payed solution.<br />Theres no security control in ActiveX.<br />We hate ActiveX!<br /><br />2. Use an stand alone application and comunicate with the browser using a common database.<br /><br />Pros:<br /><br />Easy to implement. We know how to comunicate a web page using php,jsp,etc to a database and we know how to communicate a stand alone to a database.<br />Is free.<br />Crossplatform.<br /><br />Cons:<br /><br />You will have three diferent systems to mantain. A common and accesible database, some server pages and a stand alone.<br />You will have to provide a lot of configuration information to your customer. A database conection, how to install your standalone, etc.<br />You will need to implement a polling algorithm in the standalone that reads every X time the database for changes. This is really really nasty.<br /><br />3. Using a Java Applet!<br /><br />Pros:<br /><br />You can embed the applet in the page and the user does not have to install anything. When he enters the page the applet installs automatically.<br />The applet can be signed to provide a high level of security.<br />You only need to mantain one component, the Applet!<br />Crossplatform.<br />Is free.<br /><br />Cons:<br /><br />Lately the people is stopping using applets. The applet boom has passed and now is really strange to find new implementations using this technology.<br />You need to install the JRE in the client terminal.<br /><br />Extra<br /><br />4. Using Google native code HTML5 libraries. This is really an extra because is not ready for production.<br /><br />So whats the deal? Well, you need to write an applet that sends data to the serial COM (or that sends music to your sound card, or that erase completly the harddrive, etc....). This is easy well documented, we used RXTX java library without problems. Next you need to paste it in your webpage and using javascript read the required information from the HTML controls.<br /><br />Let's see a practical examples.<br /><br /><b>WebPage example code:</b><br /><br />We can achieve the goal of communicate javascript code with the applet code to send the string characters to the COM port. To do that we need to put this code in our HTML document:<br /><br /><div style="width: 395px; height: 200px; background-color: a0ffff; color: 000000; font-family: arial; font-size: 12px; text-align: left; border: 0px solid 00000; overflow: auto; padding: 4px;"><br /><br /><script src="http://www.java.com/js/deployJava.js"></script><br /><script><br /> var parameter = "Some data you want to pass to applet at init time";<br /> var attributes = { id: 'app', MAYSCRIPT: 'true', code:'<full qualified name of the applet class ie. mx.ssf.project.MyApplet.class>', archive:'<path to look at for the .jat file>', width:430, height:490} ;<br /> var parameters = {nameOfParameterOnTheApplet: parameter} ;<br /> deployJava.runApplet(attributes, parameters, '1.6');<br /></script><br /></div><br />Ok, let's try to explain what's going on in the above sniped of code.<br /><br />The line<br /><div style="width: 395px; height: 30px; background-color: a0ffff; color: 000000; font-family: arial; font-size: 12px; text-align: left; border: 0px solid 00000; overflow: auto; padding: 4px;"><br /><script src="http://www.java.com/js/deployJava.js"></script><br /></div><br />imports a tiny javascript library file, the deployJava.js. This library contains all the code needed to integrate and deploy the applet in the web page that you want. This is a very comfortable<br />way to deploy the applet, you only need add this file and call the corresponding methods or functions that the library gives you, and it's done. If you look well, the file is on the Java.com site<br />so you don't need to download it.<br /><br />Next, the block of code:<br /><div style="width: 395px; height: 150px; background-color: a0ffff; color: 000000; font-family: arial; font-size: 12px; text-align: left; border: 0px solid 00000; overflow: auto; padding: 4px;"><br /><script><br /> var parameter = "Some data you want to pass to applet at init time";<br /> var attributes = { id: 'app', MAYSCRIPT: 'true', code:'<full qualified name of the applet class ie. mx.ssf.project.MyApplet.class>', archive:'<path to look at for the .jat file>', width:430, height:490} ;<br /> var parameters = {nameOfParameterOnTheApplet: parameter} ;<br /> deployJava.runApplet(attributes, parameters, '1.6');<br /></script><br /></div><br />Determines the way the Applet will be deployed. The first line declare a local javascript variable that we can use to send some data to the applet from the beginning like a parameter.<br /><br />In the next line, we declare the attributes for the applet. For example, the id of the applet that can referenced through the javascript script, the full qualified name for the class<br />of the applet and the path for the .jar file that contains the bytecode to tell the Java plugin where to find that class. It's important to notice the attribute "MAYSCRIPT: true",<br />this attribute it's the responsible for the communication between javascript and the applet, if this attribute is not declared, such communication can't exists.<br /><br />The next line, defines an array of parameters to be passed to the applet. Notice that we use the javascript variable (var parameter) in this array declaration. It's imperative that we declare<br />a parameter name to be used inside the applet. In this exameple that name is "nameOfParameterOnTheApplet".<br /><br />At the end, we simply call the runApplet function that it's declared in the deployJava.js file passing the attributes and parameters arrays and the version of the java run time environment that we want to use to launch the Java Applet.<br /><br />This demostrates how easy it's the implementation and deployment of a java applet.<br /><br /><br /><b>Calling to an Applet method from JavaScript.</b><br /><br />Now, I'm going to show how to call to an applet method from a javascript scrip using the example above.<br /><br />Suppose that we want to send to the COM port some string that is calculated in some maner in the HTML page. To acomplish this, first it's needed a javascript function like this:<br /><br /><div style="width: 395px; height: 120px; background-color: a0ffff; color: 000000; font-family: arial; font-size: 12px; text-align: left; border: 0px solid 00000; overflow: auto; padding: 4px;"><br /><script language="javascript"><br /> function reimprimir(){<br /> var ticket = document.forms[0].ticketArea.value;<br /> var applet = document.getElementById('app');<br /> applet.print(ticket);<br /> }<br /></script><br /></div><br /><br />This function can be called from a javascript event taking the value of a text area control of the form. The reference to the applet is obtained via getElementById function using the id defined as an attribute of the applet like showed earlier in this example. Once we have the reference to the applet, we simply call the applet method like<br />if we were programming in the java language. The applet method "print" it's defined to receive a String value, that value is the string we have in the text area component of the form. When<br />the applet method it's called, the logic it's executed as expected.<br /><br /><b>Applet Code:</b><br /><br />There is nothing especial in the applet code. It can do everything that is allowed by the Java Run Time Enviroment policy. Only one thing it's required to skip the browser sandbox. We need to sign the resulting<br />.jar file to the client browser can trust in our application.To do that, we need to do the following:<br /><br />In a command line console, perform:<br /><code><br />$ keytool -genkey -alias <alias-name><br /></alias-name></code><br /><br />Remember, the alias name can be anything you want :)<br /><code><br />$ jarsigner -keystore <path to="" the="" keystore="" file=""> -storepass <storepass> -keypass <keypass><br /><jar file="" path=""> <alias-name><br /></alias-name></jar></keypass></storepass></path></code><br />The alias-name is the same that we used in the earlier. The .keystore file usually is created in the "home" directory. (We assume a Linux operating system).<br /><br />With that done, the only step left is include the signed jar file in the Web application project to start using it.<br /><br />When the user enters your web page a popup will request the JRE plugin installation in an automated way, after that the applet will load and will ask the user for permission (this permission can be permanent based in the virtual machine configuration) and finally the displayed information in the page will start flowing via COM port. Sweet.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-15287312049497554512010-10-18T20:51:00.001-07:002010-10-18T21:23:39.607-07:00TransparencyKey and Backcolor inherited automatically to buttons and checkboxesThis is a warning more than a bug of Visual Studio. If you set the the BackColor and TransparencyKey to a WindowsForm both properties will be inherited automatically to buttons and checkboxes that lie inside this form.<br /><br />Ex.<br /><br />1. You have WindowForm1 and this Form contains button1 and checkbox1.<br />2. You set WindowForm1 BackColor an TransparencyKey to "Lime".<br />3. button1 and checkbox1 will have BackColor = "Lime" TransparencyKey = "Lime" automatically.<br /><br />That's it. So why should I consern about it? Well the problem is that when you are working in XP for example with all the visual effects activated the BackColor of all windows controls is overriden by a fancy 3d color ( "fancy" for windows :) ) but if you deactivate all the visual effects, the background of your components will be the BackColor defined.<br /><br />So? Well if you disable the visual effects and the BackColor of the buttons is transparent you can't click the buttons because like the api of TransparencyKey says, "the actions over the transparency area are sended to the back form".<br /><br />Simply, if you are using TransparencyKey in a form, don't forget to change the backColor of your buttons and checkboxes to "ControlLight" and always is a good practice to test out ALL your forms with and without effects.<br /><br />Ps. In fact, you don't need to deactivate all the effects, you just need to deactivate the one that overrides the backcolor of the components, to be honest I'm lazy to research what effect is.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-3626871259883839942010-10-14T09:49:00.001-07:002010-10-18T20:38:45.371-07:00Fluent NHibernate not autoincrement integer id'sFluent NHibernate implies from your mapping that every table integer ID is autoincremental. If you have a table with key column INTEGER "not autoincrement" every "insert" clause will fail because the insert's created with NHibernate will not include this column.<br /><br />To resolve this issue you need to set the GeneratedBy property to "Not" in your map class.<br /><br />Example:<br /><br /><code><br />Id(g => g.property).GeneratedBy.Assigned().Column("IntegerIdColumn");<br /></code><br /><br />Fluent NHibernate is an impressive and terrific library, sadly, it is terribly bad documented so easy problems like this become big time consuming issues. :(Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-78752684991570764282010-10-13T20:26:00.000-07:002010-10-13T20:43:24.971-07:00Glassfish installation broken after ubuntu update.Yesterday I updated from Ubuntu 10.04 to 10.10 and all seems to be working fine. The only problem I found is that my glassfish v2 installation is broken and when I tried to start the server from the shell I got this error:<br /><br /><code><br />./asadmin start-domain command<br />./asadmin: 19: /usr/lib/jvm/java-6-sun-1.6.0.20/jre/../bin/java: not found<br /></code><br /><br />To resolve this problem you can follow this workaround:<br /><br />First I find that after update, my official SUN JDK was replaced with OpenJDK that doesn't work quite well with glassfish. So the first step is completly uninstall the OpenJDK or at least change the current path to /usr/bin/java.<br /><br />To set the Java PATH to the official JDK execute this command and select SUN Java implementation:<br /><br /><code><br />sudo update-alternatives --config java<br />Hay 2 opciones para la alternativa java (proporcionando /usr/bin/java)<br /><br /> Selección Ruta Prioridad Estado<br />------------------------------------------------------------<br /> 0 /usr/lib/jvm/java-6-openjdk/jre/bin/java 1061 modo automático<br /> 1 /usr/lib/jvm/java-6-openjdk/jre/bin/java 1061 modo manual<br />* 2 /usr/lib/jvm/java-6-sun/jre/bin/java 63 modo manual<br /><br /></code><br /><br />Next I set the JAVA_HOME adding this lines to the end of /etc/bash.bashrc:<br /><br /><code><br />JAVA_HOME="/usr/lib/jvm/java-6-sun"<br />export JAVA_HOME<br /></code><br /><br />Finally, fix the AS_JAVA property in ../glassfish/config/asenv.conf to the correct path:<br /><br /><code><br />AS_JAVA="/usr/lib/jvm/java-6-sun"<br /></code><br /><br />Done, now glassfish should start and work flawlessly.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com3tag:blogger.com,1999:blog-6697373081813602402.post-1443479550710719562010-10-10T21:22:00.000-07:002010-10-13T22:02:46.866-07:00TransparencyKey unsupported when using double buffer.One of the easiest way to create transparent forms in Windows is using the Properties TrasparencyKey and BackColor of a WindowForm but after some hours struggling with strange behaiviors I discovered that TransparencyKey property is unsupported when enabling DoubleBuffer.<br /><br />I can't beleive Microsoft couldn't mention it in ther official API:<br /><br />http://msdn.microsoft.com/es-es/library/system.windows.forms.form.transparencykey%28VS.80%29.aspxSmart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-84475964426900027172010-09-29T22:05:00.000-07:002010-10-01T21:49:32.432-07:00TC65 NATted pseudoserver using plain sockets (Push Server)<div style="text-align: justify;">Most GPRS providers in Mexico doesn't provide a public ip and they opt to give a NATted network topology and assing a private address to each GPRS SIM. This makes impossible to create a server in a TC65 terminal using for example this example provided by blogdeelectronica.<br /><br /><span style="visibility: visible;" id="search"><span class="f"><cite>www.blogelectronica.com/<b>dyndns</b>-cinterion-siemens-modems-gpr/</cite></span></span><br /><br />To endure this ugly behavior a logical solution could be write a polling client application in the TC65 terminal that starts queryng for data a remote server every X seconds. This solution can be functional for some purposes but we found mainly three big problems that prevent us of using this.<br /><br />1. You will be sending data even if there's not work to process. (In GPRS this means $)<br />2. If there's some data to process you will not discover it until the threshold is consumed. If this threshold is to big the application will not look real time and in the opposite case you will be consuming and consuming bandwith every second processing no bussiness logic. (Our app must be close to real time)<br />3. The complexity of the aplication that will be queueing the data to process will increase. (We wanted to mantain the main structure of the desktop application that already exist)<br /><br />Our solution was creating a "pseudo-server" in the TC65 following a push communication. What does it means? This means YES!, the host that must start the comunication is the TC65 (we can't avoid this) but after the connection is stablished the remote host (desktop app in our case) will register this "pseudo-server" and will start "pushing" data into it. The secret here is DONT CLOSE THE SOCKET and if the socket is closed by any reason quickly restablish the communication channel and register again the pseudo server.<br /><br />Before giving some code about how we implemented this there are some consideration that we must exhibit:<br /><br />1. You can achieve this behavior using one socket but to have a better control we decided to create two objects, one to receive data (the pseudo-server) and one to send. This means that we have a sender TCP port and a receiver TCP port.<br />2. The TC65 dont allow to modify some socket parameters as linger, keepalive, etc., this causes some headaches because after some time if a socket haven't received or sended some data this will be closed (We discover that this magic time is 30 seconds). To avoid this we send from the remote server (the desktop app) every 27 seconds a keepalive signal. This keepalive is achived writing a single byte into de "pseudo-server".<br />3. The TC65 can't handle too many sockets at a time and don't allow to close and open quickly the sockets, if you start opening and closing sockets to quickly you will get some nasty exceptions, to avoid this we reuse the sockets and try to stablish the connection again after an unexpected failure without closing it.<br />4. To register the new pseudo server in the remote host we use the IMEI. This is a unique number that represents a single SIM that can be obtained using ATCommands.<br /><br />First the Sender, nothing new, just as many examples that can be found all over internet:<br /></div><br /><code><br />public final class Sender{<br /><br /> private OutputStream outputStream = null;<br /> private SocketConnection clientSender;<br /><br /> public void send(WorkRequest workRequest) {<br /> connect();<br /> outputStream.write(sicomCommand);<br /> }<br /> }<br /><br /><br /> private void connect() throws CommunicationChannelException {<br /> try {<br /> clientSender = (SocketConnection) Connector.open(createConnectionString(), Connector.READ_WRITE, false)<br /> outputStream = clientSender.openDataOutputStream();<br /> resourcesClosed = false;<br /> } catch (IOException iex) {<br /> closeResources();<br /> }<br /> }<br /> }<br /><br /> private void closeResources() {<br /> try {<br /> if (outputStream != null) {<br /> outputStream.close();<br /> }<br /> if (clientSender != null) {<br /> clientSender.close();<br /> }<br /> resourcesClosed = true;<br /> } catch (IOException ex) {<br /> //Do nothing<br /> }<br /> }<br />}<br /></code><br /><br />Now the Receiver or "pseudo-sever". Notice that this is a Thread and can be observed by other objects!<br /><br /><code><br />public abstract class Receiver extends Observable implements Runnable {<br /><br /> private static final int SLEEP_UNTIL_RECEIVE_TIME = 100;<br /> protected volatile boolean stopReceiver = false;<br /><br /> /**<br /> * Runs the Receiver Thread.<br /> */<br /> public void run() {<br /> startConnection();<br /> while (!stopReceiver) {<br /> receive();<br /> try {<br /> Thread.sleep(SLEEP_UNTIL_RECEIVE_TIME);<br /> } catch (InterruptedException ex) {<br /> }<br /> }<br /> postReceive();<br /> }<br /><br /> private void startConnection() throws CommunicationChannelException {<br /> try {<br /> serverListener = (SocketConnection) Connector.open(createConnectionString(), Connector.READ_WRITE, false);<br /> outputStream = serverListener.openDataOutputStream();<br /> //Send the id of the GRPS to the server<br /> outputStream.writeUTF(getIMEI());<br /> } catch (IOException ex) {}<br /> }<br /><br /> private void reconnect(boolean timeOutFlag) {<br /> try {<br /> startConnection();<br /> } catch (CommunicationChannelException ex) {<br /> try {<br /> Thread.sleep(RECONNECT_SLEEP_TIME);<br /> } catch (InterruptedException exp) {<br /> //DO nothing<br /> }<br /> }<br /> }<br /><br /> protected void receive() {<br /> try {<br /> inputSocketStream = serverListener.openDataInputStream();<br /> int bytesReaded;<br /> byte[] tcpBuffer = new byte[TCP_BUFFER_SIZE];<br /> //The next instruction read() blocks eternally until it finds data to read in the common java API<br /> //sadly the Siemens module that we are using send an idle exception wvery 30 seconds if it could not<br /> //read anything. So if the pseudo-server does not receive anything in 30 seconds it will need to register<br /> //again in the real server.<br /> while ((bytesReaded = inputSocketStream.read(tcpBuffer)) != -1) {<br /> notifyReceivedData(tcpBuffer);<br /> }<br /> } catch (Exception ex) {<br /> } finally {<br /> closeResources();<br /> }<br /> if (!stopReceiver) {<br /> //Try to reconnect after an inaccesible server or a time out<br /> reconnect(timeOutFlag);<br /> timeOutFlag = false;<br /> }<br /><br /> }<br /><br /> private void closeResources() {<br /> try {<br /> if (null != inputSocketStream) {<br /> inputSocketStream.close();<br /> }<br /> if (null != outputStream) {<br /> outputStream.close();<br /> }<br /> if (null != serverListener) {<br /> serverListener.close();<br /> }<br /> } catch (IOException ex) {<br /> //Do nothing<br /> }<br /> }<br /><br /> public void sendStopSignal() {<br /> this.stopReceiver = true;<br /> }<br /><br />}<br /></code><br /><br /><div style="text-align: justify;">In next weeks we will comunicating our TC65 terminals to a webserver using webservices. In this case we dont need the "real time" behavior so we are considering using polling, anyway we dont discard the posibility of implementing a fancier solution, in that case we will be writing our results.</div>Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-29010473289267503642010-09-29T20:43:00.000-07:002010-09-29T20:46:07.252-07:00Disabling the IPv6 in Ubuntu systems<p>May be some of you have a issue with the slow internet connection in your Ubuntu installations. This could be happend due the ipv6 support. I don't exactly know why of this behavior, but after disable it, my internet connection goes more faster. Let's see how to fix that:</p><br /><p>1.- First, make sure that the ipv6 support it's enabled on your machine. To do so, enter the following in the command line:</p><br /><p><code><strong>cat /proc/sys/net/ipv6/conf/all/disable_ipv6</strong></code></p><br /><p>That command will echoed a number, if the resulting number it's "0" means that the ipv6 support it's enabled, if the resulting number it's "1" means that the ipv6 it's disabled.</p><br /><p>2.- Now we need to add some lines to the /etc/sysctl.conf configuration file. To do so in the command line, we need to enter the following:</p><br /><p><code><strong>echo "#disable ipv6" | sudo tee -a /etc/sysctl.conf</strong></code></p><br /><p><code><strong>echo "net.ipv6.conf.all.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf</strong></code></p><br /><p><code><strong>echo "net.ipv6.conf.default.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf</strong></code></p><br /><p><code><strong>echo "net.ipv6.conf.lo.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf</strong></code></p><br /><p>3.- In the end, we need to restart the machine and the ipv6 support will be disabled.</p><br /><p></p>Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-54515077775370607172010-09-29T20:15:00.000-07:002010-10-10T21:36:00.454-07:00Installation of a development environment server on linux (part 1)Hello, we need to install a complete development enviroment for one of our customers so we decided to write a post providing step by step the line that you need to follow to have a completly functional development server.<br />This will help us documenting the process for future installations a hopefully will help someone that is requiering something similar.<br /><br />So the objective we are poursuting is:<br /><br />Install a secure intranet server, with the necesary tools for controlling the versioning of our source code, an continuos integration server that help us automatizate the process of building, unit testing, releasing, reporting, etc,<br />a repository for our librarys, builds, and maven artifacts that proxies the remote librarys reducing the use of our internet access and finally a repository for storing in an indexed and ordered way accesible for all the developers,<br />designers, etc, the documentation, extra tools, example code, etc. Also, we going to install a bug tracking system to have a precise control over the issues, bugs and failures of all of our software projects.<br /><br />A secondary and extra objective is:<br /><br />Creating a sample application in Netbeans Platform using all the servers mentioned to show the way having this tools provide a rapid development, testing and deployment enviroment.<br /><br />Prerequisites: Nothing, we will be installing everything from scrath, from the operating system to the demo proyect.<br /><br />Tools that we will use:<br /><br />1.Of course a linux distribution. In our case Debian Lenny. Why? Is easy, well documented, have a great package management system and we already are really used to this. The instructions provided could vary in for example RefHat based<br />distributions but the roots may be really similar. You know changing the apt for yum or rpm, finding configuration files in different paths but nothing drastic.<br />2.SSH for remote access to our server.<br />3.Apache to host the documentation of our projects, javadocs, and other interesting reports.<br />4.-Subversion as source control versioning system.<br />5.Hudson will be the continuos integration server.<br />6.Nexus as Maven artifact repository.<br />7. Nuxeo as document repository<br />8. MantisBT bug tracking system.<br />9. PostgreSQL 8.3 data base server.<br /><br /><br />Index:<br /><br />1.Installing and configuring the base system.<br />2.Installing and configuring the basic servers.<br /><br /><br /><span style="font-weight: bold;">1.Installing and configuring the base system.</span><br /><br />Ok, lets start. The first task is adquiring the net-install Debian Lenny package in this place.<br /><br />http://www.debian.org/distrib/netinst<br /><br />I prefeer to download only the net-install that contains the base system and all the extra software get it by demand after installation. Under Small Cds choose the correct implementation for your hardware.<br /><br />Eg.<br /><br />wget http://cdimage.debian.org/debian-cd/5.0.5/i386/iso-cd/debian-505-i386-netinst.iso<br />wget http://cdimage.debian.org/debian-cd/5.0.5/amd64/iso-cd/debian-505-amd64-netinst.iso<br /><br />You can burn it on a CD and boot from it, but also you can load it in a USB pendrive to boot from it. This is really useful in the case that in your hardware don't have available a CD-ROM drive. So, to do this we need to<br />follow the following steps:<br /><br />CAUTION: This process will delete ALL the data that are in the USB pendrive.<br /><br />1.- Download the boot.img.gz file from the /debian/dists/lenny/main/installer-i386/current/images/hd-media directory that is located in the debian mirrors: http://www.debian.org/mirror/list<br /><br />2.- We execute the following command with the pendrive umounted:<br /><code><br />zcat boot.img.gz >/dev/sdX<br /></code><br />Note: if we get a "Permission denied" output we have to do the following:<br /><code><br />sudo sh -c 'zcat ~/boot.img.gz > /dev/sdX'<br /></code><br /><br />Or this one<br /><code><br />sudo chmod 666 /dev/sdX<br /></code><br />(Replace the sdX with the correct device name of the pendrive. To know what's the device name execute the fdisk -l command. Remember that only the name of the device is required here, so the number<br />of the partition is avoided)<br /><br />3.- Mount the pendrive and copy the .iso file that we previusly downloaded in the root directory of the device. Yes, a simple copy of the .iso file.<br /><br />4.- Make sure that the motherboard of the server are available to boot from a removable USB device.<br /><br />5.- Insert the pendrive into the USB port of the server and start it. The debian install program will be displayed. Follow the instructions of the screen and we are done.<br />(Note: In the rest of this post, we assume that the user (not root) that is created in the installation process has the username demoserveradministrator)<br /><br />Now that the base system is installed we need to take some steps before installing any program or server.<br /><br />Log in as the user you created (no root) in this demo demoserveradministrator and after that supplant root using the command and providing the root password.<br /><br /><code><br />su<br /></code><br /><br />First of all, lets remove the line that points to the installation cd from our software repositories list, if you don't do this every time you try to install software the apt-get command will ask you to insert<br />the first cd of debian. If thats not a problem for you ommit this step.<br /><br /><code><br />nano /etc/apt/source.list<br /></code><br /><br />Comment the line that points to the installation cd.<br /><br />In addition to remove the CD repository line in the sources.list file, you can add more repositories.These work for us:<br /><br />## Debian Stable (Lenny)<br />deb http://ftp.es.debian.org/debian/ stable main contrib non-free<br />deb-src http://ftp.es.debian.org/debian/ stable main contrib non-free<br />## Actualizaciones de seguridad<br />deb http://security.debian.org/ stable/updates main contrib<br />deb-src http://security.debian.org/ stable/updates main contrib<br /><br />Save and exit.<br /><br /><code><br />apt-get update<br /></code><br /><br />Ok, our software database is up to date. Now lets change some parametters to enhance the security of the system.<br /><br /><code><br />apt-get install sudo<br /></code><br /><br />Now add your demoserveradministrator to sudoers archive and give him all the privileges.<br /><br /><code><br />visudo<br /></code><br /><br />And add this line:<br /><br /><code><br />demoserveradministrator ALL=(ALL) ALL<br /></code><br /><br />save the file and after that type:<br /><br /><code><br />exit<br /></code><br /><br />to finish suplanting root. Now<br /><br /><code><br />sudo passwd -l root<br /></code><br /><br />to lock root.<br /><br />Ok, what we did in the last lines was locking the root account this means that after this point you cant login to the server using "root" or "su", this is a healty practice because if a hacker tries to break our server<br />the first step he or she will try is breaking our root password but if root is locket he will need to deduce first the user name that have the root priviledges. Warning, from this point the demoserveradministrator is just<br />like root so choose a hard password and never create more than one user with the ALL=(ALL) ALL options, that would be worse than never install sudo.<br /><br />NOTE: To unlock root just type at anytime:<br /><br /><code><br />sudo passwd root<br /></code><br /><br />and provide a new password for root.<br /><br />Configure some network parametters:<br /><br />The demo network topology...<br /><br />## Here should be placed the diagram of the network##<br /><br />This will be a dedicated server so we really recomend you to avoid using dhcp and set a static ip to the server.<br /><br /><code><br />nano /etc/network/interfaces<br /></code><br /><br />And comment the iface eth0 inet dhcp line and replace it with your network preferences:<br /><br /><code><br />iface eth0 inet static<br /> address 192.168.1.10<br /> netmask 255.255.255.0<br /> network 192.168.1.0<br /> broadcast 192.168.1.255<br /> gateway 192.168.1.1<br /></code><br /><br />After that restart the network services.<br /><br /><code><br />sudo /etc/init.d/networking restart<br /></code><br /><br />At this stage you should test the static configuration pinging some host inside your intranet and some in the internet. If everithing is alraight proceed.<br /><br />Next, we will install a firewall, this will use the computer as a intranet server but that doesn't mean you should not install a firewall. Is easy, quick and really becomes your server more secure. This configurations<br />are very dependent of your intranet network topology anyway I will give an example using this simple network topology.<br /><br /><code><br />apt-get install shorewall<br /></code><br /><br />Enable shorewall in startup.<br /><br /><code><br />sudo nano /etc/default/shorewall<br /></code><br /><br />and change the value of startup var to 1<br /><br /><code><br />startup=1<br /></code><br /><br />Now copy the example configuration files to use them as template:<br /><br /><code><br />cp /usr/share/doc/shorewall-common/default-config/zones /etc/shorewall/<br />cp /usr/share/doc/shorewall-common/default-config/interfaces /etc/shorewall/<br />cp /usr/share/doc/shorewall-common/default-config/hosts /etc/shorewall/<br />cp /usr/share/doc/shorewall-common/default-config/policy /etc/shorewall/<br />cp /usr/share/doc/shorewall-common/default-config/rules /etc/shorewall/<br /></code><br /><br />And modify the /etc/shorewall/zones<br /><br /><code><br />sudo nano /etc/shorewall/zones<br /></code><br /><br />Uncomment the fw zone if is commented and and this two zones after fw<br /><br /><code><br />fw firewall<br />net ipv4<br />loc ipv4<br /></code><br /><br />Save and exit, now modify interfaces file:<br /><br /><code><br />sudo nano /etc/shorewall/interfaces<br /></code><br /><br />Add the unique network interface to the file:<br /><br /><code><br />- eth0 detect dhcp,tcpflags,logmartians,nosmurfs,blacklist<br /></code><br /><br />Save and exit, now modify hosts file:<br /><br /><code><br />loc eth0:192.168.1.0<br /></code><br /><br />Save and exit, now modify the policy file:<br /><br /><code><br />fw all ACCEPT info<br />all all REJECT info<br /></code><br /><br />Save and exit, now modify the rules file:<br /><br /><code><br />Ping/ACCEPT loc $FW<br />ACCEPT loc $FW tcp 80<br />ACCEPT loc $FW tcp 54352<br />ACCEPT loc $FW tcp 8080<br />ACCEPT loc $FW tcp 21<br /></code><br /><br />##Add the ports missing#<br /><br /><br />Now the time of the truth, run:<br /><br /><code><br />sudo /etc/init.d/shorewall start<br /></code><br /><br />If you have a typo in an archive the startup will fail and you should verify shorewall init log to find the error.<br /><br /><code><br />tail /var/log/shorewall_init.log<br /></code><br /><br />Ok, now a brief description of what we done in the last lines:<br /><br />1. In the zones file we defined three zones. One for the firewall, one for the internet and subnets that not belong to our intranet and a loc for our local network or intranet.<br />2. In interfaces we informed to shorewall that we have only one interface and that all the zones are accesible trough that unique eth0 interface.<br />3. In the hosts file we provided the subnet that covers our intranet.<br />4. In policy we informed shorewall that the server can access to the internet and intranet but anything outside the firewall should not access. (This could appeer like an error because how will our intranet<br />users are supposed to access the services hosted in the server? Dont worry we add some exceptions in the next archive )<br />5. Finally in rules we provide some exception. (All for the intranet users) For example we permit the pings that comes from the intranet, we opened the port 80 to access apache, etc.<br /><br />A small parenthesis:<br /><br />What ports we will be using?<br /><br />80 for APACHE<br />54352 for SSH<br />21 for FTP<br /><br />#Add the ports missing#<br /><br />Testing the configuration:<br /><br />After starting the firewall if the configuraion is ok you should be able to:<br /><br />1. Ping from the server to any place on earth.<br />2. Ping from the intranet 192.168.1.X to the server.<br />3. Access one of the ports that are configured in rules archive from the intranet. (This will not work until a server is listening to one of those ports, be pantient)<br /><br />After starting the firewall you should not be able to:<br /><br />1. Ping from any other subnet that is not 192.168.1.X obviuslly internet included.<br />2. Access any other port that is not listed in rules from any place. Including the intranet itself.<br /><br />Once again, the configuration of shorewall depends a lot of your network topology, but is a really easy firewall and there are tons of documentation of this in the net, so for the firewall configuration we are done.<br /><br />Ok, administrating the server locally is a painfull so lets install ssh to access the server from our personal computer.<br /><br /><code><br />sudo apt-get install ssh<br /></code><br /><br />Change port 22 for 54352. Using a different port that the default increase the security of the server. Disable X11 Access, the command line is just enough an once again limiting to command line improves the server security.<br />Disable root access (This could be skipped because we locked root some steps below but this will not hurt you), allow only remote access to demoserveradministrator, enable the welcome Banner for SSH session. To do all that<br />you should have this lines in sshd_conf.<br /><br /><code><br />sudo nano /etc/ssh/sshd_conf<br /></code><br /><br /><code><br />Port 54352<br />X11Forwarding no<br />PermitRootLogin no<br />AllowUsers demoserveradministrator<br />Banner /etc/issue.net<br /></code><br /><br />Save and exit and now modify the access banner with a nice scarecrow message and usage contract:<br /><br /><code><br />nano /etc/issue.net<br /></code><br /><br />""""""""""""""""WARNING"""""""""""""""""""""<br />You are loggin to a server of YOURCOMPANY if<br />you logged to this terminal by error<br />loggoff inmediatly...etc... etc... more and<br />more messages....<br /><br />Run ssh server:<br /><br /><code><br />/etc/init.d/ssh restart<br /></code><br /><br />Done... now try accessing using putty or a linux terminal with ssh client in your intranet using a command like:<br /><br /><code><br />ssh 192.168.1.10 -l demoserveradministrator -p 54352<br /></code><br /><br />If you follow the steps you should log in to the server and see the scary welcome message.<br /><br />Almost done!! one more server and we finish the base system installation!<br /><br />Having an ftp server always is usefull, you can copy files using SSH but wen you want to copy tons of files this can become tiring. We will install proftp that is a fpt server for linux systems that<br />have a really easy configuration.<br /><br /><code><br />sudo apt-get install proftpd<br /></code><br /><br />This will prompt a configuration wizard. Select the initd configuration (but remember we are not installing the ftp server to provide an ftp service to our users we are installing this to have a confortable way for the administrator<br />for uploading and downloading files to and from the server).<br /><br />Now configure the server:<br /><br /><code><br />sudo nano /etc/proftpd/proftpd.conf<br /></code><br /><br />1. Disable ipv6<br />2. Change the server name to Demo Development Sever<br />3. Jail the users to their home to increase security<br />4. Once again add the scarecrow message<br />5. Add some tweeks to the ftp navigation system.<br /><br /><code><br />UseIPv6 off<br />ServerName "Debian"<br />DefaultRoot ~<br />DisplayLogin /etc/issue.net<br /><br /><br />#Tweeks to the ftp navigation system<br />IdentLookups off<br />UseReverseDNS off<br />ListOptions "" maxdepth 3<br />ListOptions "" maxdirs 10<br />ListOptions "" maxfiles 1000<br />AllowOverride off<br /></code><br /><br />Now, restart the service:<br /><br /><code><br />sudo /etc/init.d/proftpd restart<br /></code><br /><br />And try logging from your intranet to the ftp server using an ftp client like filezilla.<br /><br />Using a web browser:<br /><br /><code><br />ftp://demoserveradministrator:password@192.168.1.10<br /></code><br /><br />PLUS: Navigating in console mode can be easier if you enable bash colors. To do that just modify /home/demoserveradministrator/.bashrc and uncomment the force colors clause.<br /><br />Congratulations you now have a secured (you could tweek a lot more the security but this will be an intranet server, so this should be enogh), accesible, fast and relaible linux debian base system.<br /><br /><span style="font-weight: bold;">2.Installing and configuring the basic servers.</span><br /><br />The firts server we are going to install is the apache server.<br /><br /><code><br />sudo apt-get install apache2<br /></code><br /><br />To avoid dispaching version info of our server to the clients we need to open /etc/apache2/apache2.conf and modify or add this lines:<br /><br /><code><br />ServerSignature Off<br />ServerTokens Prod<br /></code><br /><br />Now lets create a webadmin user.<br /><br /><code><br />sudo useradd webadmin<br /></code><br /><br />We need to change the apache folder to the www folder of the webmaster user.<br /><br /><code><br />sudo nano /etc/apache2/sites-available/default<br /></code><br /><br />Change the DirectoryRoot from /var/www/ to /home/webmaster/www/ and do the same to the Directory param.<br /><br />Now open your ftp clien (filezilla for example), and login to the server using webmaster user. Create a www folder in the webmaster home directory and inside www put an index.html file with your welcome homepage.<br /><br />Restart the apache service:<br /><br /><code><br />sudo /etc/init.d/apache2 restart<br /></code><br /><br />Now from any host in your intranet using a web browser you can see the welcome homepage.<br /><br />At this point we have a basic Apache web server. To make it more useful we need to install the PHP distribution environment addon to allow to our server to dispatch dynamic content sites. Let's do the<br />following:<br /><br /><code><br />sudo apt-get install php5 php5-pgsql php5-gd<br /></code><br /><br />The last command will install the PHP version 5 distribution and a connector module to a PostgreSQL data base server. The "php5" package makes the configuration needed between the Apache server and the PHP<br />distribution automaticly, so we don't need to do anything more here.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-81128940689457633032010-08-16T22:08:00.000-07:002010-10-23T01:07:40.102-07:00Some thoughts about byte data types in Java and C#We developed a simple communication application between JME and C# using sockets. We send some ASCII data from a C# to a java midlet, this data can contain printable ASCII (from 0 to 128) and non printable ASCII (from 129 to 255).<br /><br />Everything was working smooth until we had to extract some bytes from the frame in the java midlet and compare them to non printable ASCII. Example:<br /><br /><code><br />byte x =byte[30]; //This position contains a non printable Happy Face ASCII<br /><br />if(x == 254){<br />//This condition never is true<br />}<br /></code><br /><br />This happen because the java byte is signed, this means that this goes from -127 to 128, in the other hand c# byte is non-signed (from 0 to 255). Our first aproach was to convert all the byte arrays in java to short arrays adding 256 to negative ones, but thats not really necesary.<br /><br />The rule is easy, it doesn't matter what operation you are doing over the signed byte, adding, substracting, multiplying, etc, always the result will be the same even if it is signed or unsigned. Why? The sign is in your mind! The sign is no more than an interpretation. But what happend when you want to compare this values or print them? In that case this will not work because casting a negative byte to char in java is not the same as deleting the sign.<br /><br />Another example:<br /><br /><code><br />char x = (char)-1;<br /><br />//x is not 255.<br /></code><br /><br />Whats the correct way to proceed?<br /><br />Easy, you need to add, substract, multiply, etc signed or unsigned bytes? Don't worry do it, it will work always and even if this is signed or unsigned you will get exactly the same result. You need to compare the chars obtained? Delete the sign of the signed byte usign this line:<br /><br /><code><br />byte x = -1;<br />char y = (char)(x & 0xFF)<br /></code><br /><br />Sweet..Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-75735199349644164992010-07-07T13:42:00.000-07:002010-07-07T14:10:40.010-07:00Random TC65 shutdownsAfter some time our TC65 GPRS terminal shuts down without giving any kind of message or error. We don't get the ^SHUTDOWN line neither a temperature or voltage warning. After some research in internet we discovered that is a problem that other people have suffer but in the few threads that can be found regarding this hardware you will not found any long term solution (Even a lot of this blog entries are already locked).<br /><br />We were struggling for a long time but finally we have found a common pattern in the deployment actions of the midlet in the TC65 that could be propitiating this behavior.<br /><br />First of all, we weren't using the last emulator (provided in our case by CINTERION), we were using a legacy emulator of SIEMENS. In the same way the firmware was out of date, we were working with 2.0 firmware instead 3.0.<br /><br />Using the new emulator and the new firmware the problem appear a lot less, but wasn't a complete solution, The real solution is making the deployments without using the netbeans RUN command.<br /><br />We are not sure why deploying the midlet using netbeans makes the midlet stop working after some random time, this is a really strange behavior but after deploying manually copy pasting the jar and jad files the terminal never stops working.<br /><br />Once again we can't give a real explanation of why this error occurs but for the moment this is working for us and let us keep forward our development.Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0tag:blogger.com,1999:blog-6697373081813602402.post-1599636500587004062010-06-14T21:45:00.000-07:002010-07-07T13:28:32.640-07:00Proftpd slow accessWe had a proftp server in debian working with no problems for half a year and one day seems to stopped working. When trying to access using filezilla we got a waiting for hello message and after 20 seconds a timeout.<br /><br />The first impression was that the server was broken but after incrementing the timeout in the options of filezilla to one minute we were able to access the ftp, but this was painfully slow. After some troubleshooting we start looking for changes in the server, network, etc. and we discovered that the only thing that changed was an intranet DNS that we installed using Zeroshell to be able to resolve intern hostnames. The solution was disable the reverse DNS resolution in the proftp config file and add a couple of tunning about the number of files and folders that can be get at a time from the ftp server.<br /><br />Add this lines to the end of the proftp conf file and everything starts working just perfectly.<br /><br /><code>IdentLookups off<br />UseReverseDNS off<br />ListOptions "" maxdepth 3<br />ListOptions "" maxdirs 10<br />ListOptions "" maxfiles 1000<br />AllowOverride off</code><br /><br />Source of the solution:<br /><br />http://www.howtoforge.com/forums/showthread.php?s=dbf8616988bb2215f01ef3f8f84c0bcc&t=1886&page=2Smart Software Factoryhttp://www.blogger.com/profile/17986414706350036569noreply@blogger.com0