Thursday, December 20, 2012

UICollectionView prior to iOS6

Recently we had the need of presenting our entries in a kind of gallery in one of our apps. This is not supposed to be a big problem, as in iOS6 the new UICollectionView was introduced, however we were not allowed yet to drop the support for iOS5 so we were basically screwed.

By looking at a solution to this problem i found the PSTCollectionView that was developed by Peter Steinberger for one of his projects, but fortunately he put it open source onto GitHub.

From the functionalities and the look&feel its almost a 1:1 copy of the native UICollectionView but it works all the way down to iOS 4.3, which is great, as we just need it to work on iOS5. The best feature in my opinion is the full interoperability with the native UICollectionView classes and helper classes.

This means, that you're able to use native classes if they are present (so if its running on >iOS6.0) otherwise there is a build in fallback to the custom PSTCollectionView classes. All you need to do in your code (beside providing the library files) is to change the definitions from e.g. UICollectionView to   PSUICollectionView, UICollectionViewDelegate to   PSUICollectionViewDelegate, and so on. The rest is performed in the background.

Installing it into your project is simple as well, mainly if you use CocoaPods, which I'll discuss in a future article.

Thursday, December 13, 2012

Change the SSID on your Telecom Italia WiFi modem/router

If you live in Italy (like me) and your ADSL is provided by Telecom Italia, then you probably got this wireless router as a welcome gift. 
Initially I though that it is, like any other router provided by the phone companies, a castrated version of a badly working modem. Therefore I just put it into its box and away.

However lately my usual router stopped working and as I needed an immediate substitute, that gift came in my mind. When I started configuring it through its loveless GUI I felt confirmed in my aversion against it, however when you're willing to invest a bit more time into it you'll find more and more options present in Netgear or Fritz!Box routers, just badly presented in that awful GUI.

You can have DynDNS, Port-Forwarding, 256-WLAN-encryption, Print server via USB, ... so basically everything you need...

...Except one thing. By default your WLAN is called something like "Telecom-123456" which could be kind of distracting  so that your computers will find 10 or more WLAN with almost the same name.

So, basically I had to change the name of it. Simple you guess? Me too, however there is no option to change the name of the WLAN in that GUI which was really surprising me, but there is a solution to that problem too.

Basically just create a backup of your routers settings using the GUI, which will be saved as something like "AGConfig20121212.kry". That one is an encrypted version of the settings which we are going to decrypt using the following command

openssl aes-128-cbc -K 65316532656263323039373831383630 -nosalt -iv 0 -d -in AGConfig20121212.kry -out AGConfig20121212.xml

In the XML then you can just search for the name of your WLAN and change it to a name you like it to be. After that we need to encrypt the changed file using the following command (note that "-e"(encrypt) now changed to "-d"(decrypt) and the filenames are in reversed order)

openssl aes-128-cbc -K 65316532656263323039373831383630 -nosalt -iv 0 -e -in AGConfig20121212.xml -out AGConfig20121212.kry

Now you can just restore your router with this newly created file (pay attention on your power supply during that action) and provided that you did not change any other values in the file, your router starts up in the same configuration as before just with a new SSID.

Tuesday, September 25, 2012

iOS - Hide settings below tableView

Recently I posted a question on StackOverflow, on how you could possibly hide the settings menu below a tableview and let it be uncover from the top as it is done in the actual AppShopper App for iPhone.


I got some hints on how this could be done, but at the end I had to program the overall solution by myself. I answered my question already there, so you could probably just take the code from there, but as I find it quite interesting, and it could be used also in other projects I prefer to have it here in my blog.

I just put both views on the controller in the storyboard (the views get created in order, so the last in the list will be on top when the controller is shown) one over the other. Then you need to define a trigger for the uncover/cover function, which could be either a button, or a slide gesture or whatever. This trigger then needs to perform the following code

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve: UIViewAnimationCurveEaseOut];
CGRect newFrame = self.newsTableView.frame;
newFrame.origin.y = newFrame.origin.y + self.subview.frame.size.height;
[self.subView1 setFrame:newFrame];
[UIView commitAnimations];

Maybe you need to adjust something else in your case, but more or less you should be done!

Monday, September 17, 2012

UILabel - Change Vertical Alignment

Lately I promised you more posts about my experience in iOS programming. Unexpectedly my company needs lots of iOS-apps so I had no time to share my new knowledge with you which I want to catch up right now starting with a problem I faced today.

The Xcode is a great environment to visually develop iOS apps, but like any other IDE it has some limitations. Today I tried to create a custom UITableViewCell containing some UILabels and UIImages. One of this labels should show two lines of text with truncated tail (with "..." as suffix).

Up to here no problem at all, as long as you are happy with the apple defined standard behaviour of multiline labels. In a usual label if the text does not cover both lines (perhaps it covers in portrait, but not in landscape) then the label shows just one line with centred vertical alignment. In most of the cases this could be an option, however it does not fit into the design for our app. U, like me probably think, that it should not be a problem to change the vertical alignment, however this behaviour is not easy to change.

I found some posts in which other developers suggest to use the sizeToFit method of the UILabel. Despite that, generally this would be a solution, in my case the label is contained into a UITableCellView which adds one more level of difficulty to the problem. In a UITable the Cells are not created for each data item, but reused several times and so it would reuse the resized label over and over again, and as I saw from several tests, even though I called sizeToFit after each assignment, the Label is not reset.

In other posts I found the hint, that I have to reset the frame to its initial size before calling sizeToFit, in order to have it working correctly. That's already the right way, but what's the size to set it to? The one defined in the storyboard? Close, but what if you have more than one storyboard?

The solution is to define the hight and width according to the autosized properties in the storyboard reduced by the number of remaining lines times the hight of a line. The latter needs to be calculated using the font and the font size.

    [cell.myLabel setText:[dataDictionary valueForKey:kMyLabel]];
    CGSize titleSize = [cell.
myLabel.text sizeWithFont:cell.myLabel.font constrainedToSize:CGSizeMake(cell.frame.size.width,40.0f) lineBreakMode:cell.myLabel.lineBreakMode];  
    //Adjust the label the the new height
    CGRect newFrame = cell.eventTitleLabel.frame;
    newFrame.size.height = titleSize.height;
    cell.myLabel.frame = newFrame;

The code is quite self explaining, except maybe the "40.0f". This value is just saying tht in my case the height of the Label should be limited to 2 lines in my case. This could be improved by dynamically calculate the size of one row times the lines you want to display.

UPDATE:
That's more or less the same solution I came up with implemented in a Category, which makes it simple and reusable.

Friday, August 03, 2012

Back On Mac (Finally)

After a lot of posts on Hibernate, Spring, CAS and some other topics I'll start to blog on something new now.

Recently we got the task to develop a mobile application for our java based system. As I'm already quite a good Java programmer I decided to go for something new (at least for me) and take over the part of the iOS programming.

Of course when you decide to go mobile now you cannot just code for the iOS platform, but you'll have to consider also Android and slowly also the Windows Mobile 7 (and 8) platform. Despite that it would be nice to develop on every platform in parallel we are quite limited in time and man power, so we will focus now just on iOS and Android whereas the later will be developed by a workmate (unfortunately I could not take over everything :-)

Due to this decisions you'll probably find most of the future posts on iOS related topics, however if we'll find some fancy solution to a common Android problem I'll post it too.

Till now the most funny thing that I can post regards my preparation or better my learning of the Objective C language and my experience in the first week. As I know already since last week that I'll go to work on iOS I was looking for good tutorials and similar stuff that simplifies the first steps in a new coding language.

To make a long story short; All you'll need to jump into the topic is some time to watch this tutorial that you'll find in iTunes iPad and iPhone Application Development (HD) by Paul Hegarty. As you're starting to develop for this platform you probably have already an iPad on which you can watch it from you sofa or your happy place or wherever you like.

Of course its not the first new language that I learn (beside Java I know C/C++ which by the way makes it really simple to understand Objective-C, Python, Cobol, Pl/1 and some others) so its not that difficult for me to switch context, however after one week of coding my App is already able to fetch data from our server via Rest, navigate through various layers (like a tree structure) al the way down to the content and sow that one into a WebView container. And all this already for iPhone and iPad, which should give you an impression on how good the Stanford tutorial really is.

So, as this post is just intended as a sort of introduction to my new studies I'll stop here, but stay tuned for new posts on how to structure your MVC-iOS application, how to communicate from you iOS app via REST to a server and many other intresting topics.

Tuesday, July 10, 2012

CAS - Restlet Access

Today we had to do another modification to the standard CAS login system. As you might know form my older posts we had to add the possibility of using more than one LDAP in our system and some other modifications in order to view the various login pages depending on where you're coming from.

Exactly this changes need to be considered whenever you have to add some more functionality to your CAS system. like the "Remember-Me" function we introduced lately or in this case as we need to offer login via REST calls.


Despite that, the standard solution would work out of the box without the changes discussed above, we cannot do without them, so we had to propagate our changes through the REST plugin. This means that we had to add a new parameter to the REST login call.

POST /cas/v1/tickets HTTP/1.0
username=battags&password=password&domain=domain1&additionalParam1=paramvalue

This call needs to be parsed correctly and its values need to be stored in our custom credentials class (DomainUsernamePasswordCredentials or RememberMeDomainUsernamePasswordCredentials) which are able to hold the value for domain and if activated, the "RememberMe" option.

Fortunately adding support for this can be done by changing just a single class, which is the TicketResource. By default this class creates an Instance of  "UsernamePasswordCredentials", which needs to be replaced by one of the custom classes mentioned above.
package org.jasig.cas.integration.restlet;


import org.jasig.cas.authentication.principal.Credentials;
import org.jasig.cas.authentication.principal.RememberMeDomainUsernamePasswordCredentials;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.support.WebRequestDataBinder;


public class DomainTicketResource extends TicketResource {


 private static final Logger log = LoggerFactory.getLogger(DomainTicketResource.class);


 @Override
 protected Credentials obtainCredentials() {
  final UsernamePasswordCredentials c = new RememberMeDomainUsernamePasswordCredentials();
  final WebRequestDataBinder binder = new WebRequestDataBinder(c);
  final RestletWebRequest webRequest = new RestletWebRequest(getRequest());
    binder.bind(webRequest);
  return c;
 }
}
And that's it basically. The only thing that's missing is to exchange the existing bean definition of TicketResource in restlet-servlet.xml with the definition of DomainTicketResource and it will work.

Tuesday, May 29, 2012

Apple TV Untethered Jailbreak iOS5.1.1 (5.0.1)

Following the instructions from my former post  its now possible to jailbreak the ATV2 running the latest version of iOS (5.1.1) .
Basically its still the same tool, provided by firecore that does the jailbreaking. The instructions to install the nitoTV software center are also still valid, however the XBMC installation procedure is a little more difficult because the version provided by nitoTV is not yet compatible with the new iOS.

Fortunately the actual nightly build is quite stable and works as expected. To install it you need to connect to the ATV via SSH as you've done to install nitoTV and issue the following list of commands.

apt-get install wget 
wget -O- http://apt.awkwardtv.org/awkwardtv.pub | apt-key add - 
echo "deb http://apt.awkwardtv.org/ stable main" > /etc/apt/sources.list.d/awkwardtv.list 
echo "deb http://mirrors.xbmc.org/apt/atv2 ./" > /etc/apt/sources.list.d/xbmc.list
apt-get update
mkdir -p /Applications/AppleTV.app/Appliances
apt-get install org.xbmc.xbmc-atv2
mkdir -p /Applications/XBMC.frappliance
wget http://mirrors.xbmc.org/apt/atv2/deb/org.xbmc.xbmc-atv2_11.0-3_iphoneos-arm.deb
dpkg -i org.xbmc.xbmc-atv2_11.0-3_iphoneos-arm.deb
rm org.xbmc.xbmc-atv2_11.0-3_iphoneos-arm.deb
apt-get install com.nito.nitotv 
apt-get install com.nito.updatebegone
reboot


And that's it again. On the ATV's main screen there should be the well know XBMC-icon which starts your new media center.

Tuesday, March 20, 2012

CAS - authentication vs. principal resolver mismatch

Lately we found an annoying bug in our CAS login system. If you read already some of my older posts you might know that we had to login against multiple domains in our system which resulted in a complex configuration in our deployerConfigContext.xml.

A sample of that is shown here:

<!-- AUTHENTICATION MANAGERS -->
<bean id="authenticationManagerFirst" class="org.jasig.cas.authentication.AuthenticationManagerImpl">
<property name="credentialsToPrincipalResolvers">
<list>
<ref bean="credentialsToPrincipalResolverFirst" />
<ref bean="credentialsToPrincipalResolverSecond" />
<bean
class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver"
p:attributeRepository-ref="attributeRepositoryJdbc" />
<bean
class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
</list>
</property>
<property name="authenticationHandlers">
<list>
<ref bean="authenticationHandlerFirst" />
<ref bean="authenticationHandlerSecond" />
<ref bean="authenticationHandlerJdbc" />
<bean
class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient" />
</list>
</property>
</bean>

In our opinion this would work like this, that it goes through the list of authentication handlers looking for the first one that could authenticate the users credentials. Lets say it was found in authenticationHandlerSecond it would go and look for the right principal resolver to get all the needed attributes to append to the response.

Unfortunately the later step does not know which authentication handler was used in first step, so it starts over to go through the list until it finds a resolver that knows about the username that wants to get access. In this step there is no more password involved so it could be that if the first principal resolver knows about the same username and returns that parameters (even though the password is not the same!). Furthermore if the principal belongs to another user you'll be logged in as that one. Quite bad!

Fortunately the solution is quite simple. Instead of using the standard AuthenticationManagerImpl we create our own manager class like the following

public final class DomainAuthenticationManagerImpl extends AbstractAuthenticationManager {
/** An array of authentication handlers. */
@NotNull
@Size(min = 1)
private List authenticationHandlers;
/** An array of CredentialsToPrincipalResolvers. */
@NotNull
@Size(min = 1)
private List credentialsToPrincipalResolvers;
@Override
protected Pair authenticateAndObtainPrincipal(final Credentials credentials) throws AuthenticationException {
 

This one is basically a copy of the original AuthenticationManagerImpl just having the following changes

// save the position in which the authenticationHandler was found
int authenticationHandlerPosition = 0;
for (final AuthenticationHandler authenticationHandler : this.authenticationHandlers) {
if (authenticationHandler.supports(credentials)) {
[..]
}
authenticationHandlerPosition++;
}
[..]
if (!authenticated) {
if (foundSupported) {
throw BadCredentialsAuthenticationException.ERROR;
}
throw UnsupportedCredentialsException.ERROR;
}
// Not check in every CredentialsToPrincipalResolver, but only in the one on the same position in the list where the authenticationHandlerhas been found above
// for (final CredentialsToPrincipalResolver credentialsToPrincipalResolver : this.credentialsToPrincipalResolvers) {
if (authenticationHandlerPosition >= 0
&& authenticationHandlerPosition < this.credentialsToPrincipalResolvers.size()) {
CredentialsToPrincipalResolver credentialsToPrincipalResolver = this.credentialsToPrincipalResolvers
.get(authenticationHandlerPosition);
[..]

With this small changes we can remember on which position the authentication handler was found and just test with the resolver on the same position in the list of resolvers.

Wednesday, February 22, 2012

Convincing IE to not remove window.location.hash on a redirect

Our system has to work well with the most used browsers. This is usually not a big deal as longas you don't check your page on IE. Unfortunately it is still among the most used ones, so any serious web page has to consider it.

Lately we faced the problem, that whenever spring security has decided that the login is not valid anymore, and redirected the user to the login page the query string and the hash are removed (only in IE) and the user looses the reference to the page he/she was before.

There are two solutions to this problem. The first is just a parameter in the authentication entry point of your website

<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint" >
<constructor-arg name="loginFormUrl" value="/login.jsf" / >
<property name="useForward" value="true"/ >
</bean>

Forwarding instead of redirecting leaves the URL unchanged when the page displays the login page, so IE has no change to remove the parameters. Unfortunately this solutions shows the login page probably on every page of your website. If the user uses a password inserting tool based on URLs this will not work anymore, and of course it is not transparent for the user to enter its credentials once on the login page and than on another page.

The second solution I found on the Internet (so its not really my Idea). Basically it consists of adding a new filter in the filter chain on first position
<custom-filter ref="retainAnchorFilter" position="FIRST" />
This filter is than defined like this

<bean id="retainAnchorFilter" class="it.unibz.ict.utils.RetainAnchorFilter">
 <constructor-arg name="storeUrlPattern" value="${local.url}/login.*" />
<constructor-arg name="restoreUrlPattern" value=".*/${local.appname}/.*" />
<constructor-arg name="cookieName" value="TARGETANCHOR" />
</bean>
This filter will than store the hash when the URL matches the storeUrlPattern and restore it on the restoreUrlPattern. Actually we don't use the restore feature, because on the login page we read the parameters into a hidden field and send it using the normal form submission which fits better into our architecture, but for this sample I preferred to have it complete.

public class RetainAnchorFilter extends GenericFilterBean {
private final String storeUrlPattern;
private final String restoreUrlPattern;
private final String cookieName;
public RetainAnchorFilter(String storeUrlPattern, String restoreUrlPattern, String cookieName) {
this.storeUrlPattern = storeUrlPattern;
this.restoreUrlPattern = restoreUrlPattern;
this.cookieName = cookieName;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
if (response instanceof HttpServletResponse) {
response = new RedirectResponseWrapper((HttpServletResponse) response);
}
chain.doFilter(request, response);
}
/**
* HttpServletResponseWrapper that replaces the redirect by appropriate Javascript code.
*/
private class RedirectResponseWrapper extends HttpServletResponseWrapper {
public RedirectResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public void sendRedirect(String location) throws IOException {
HttpServletResponse response = (HttpServletResponse) getResponse();
String redirectPageHtml = "";
if (location.matches(storeUrlPattern)) {
redirectPageHtml = generateStoreAnchorRedirectPageHtml(location);
} else if (location.matches(restoreUrlPattern)) {
redirectPageHtml = generateRestoreAnchorRedirectPageHtml(location);
} else {
super.sendRedirect(location);
return;
}
response.setContentType("text/html;charset=UTF-8");
response.setContentLength(redirectPageHtml.length());
response.getWriter().write(redirectPageHtml);
}
private String generateStoreAnchorRedirectPageHtml(String location) {
StringBuilder sb = new StringBuilder();
sb.append("<html><head><title>Redirect Page</title>\n");
sb.append("<script type=\"text/javascript\">\n");
// store anchor
sb.append("document.cookie = '" + cookieName + "=' + window.location.hash + '; path=/';\n");
// redirect
sb.append("window.location = '" + location + "' + window.location.hash;\n");
sb.append("</script>\n</head>\n");
sb.append("<body><h1>Redirect Page (Store Anchor)</h1>\n");
sb.append("Should redirect to " + location + "\n");
sb.append("</body></html>\n");
return sb.toString();
}
@SuppressWarnings("unused")
private String generateRestoreAnchorRedirectPageHtml(String location) {
StringBuilder sb = new StringBuilder();
sb.append("<html><head><title>Redirect Page</title>\n");
sb.append("<script type=\"text/javascript\">\n");
// generic Javascript function to get cookie value
sb.append("function getCookie(name) {\n");
sb.append("var cookies = document.cookie;\n");
sb.append("if (cookies.indexOf(name + '=') != -1) {\n");
sb.append("var startpos = cookies.indexOf(name)+name.length+1;\n");
sb.append("var endpos = cookies.indexOf(\";\",startpos)-1;\n");
sb.append("if (endpos == -2) endpos = cookies.length;\n");
sb.append("return unescape(cookies.substring(startpos,endpos));\n");
sb.append("} else {\n");
sb.append("return false;\n");
sb.append("}}\n");
// get anchor from cookie
sb.append("var targetAnchor = getCookie('" + cookieName + "');\n");
// append to URL and redirect
sb.append("if (targetAnchor) {\n");
sb.append("window.location = '" + location + "' + targetAnchor;\n");
sb.append("} else {\n");
sb.append("window.location = '" + location + "';\n");
sb.append("}\n");
sb.append("</script></head>\n");
sb.append("<body><h1>Redirect Page (Restore Anchor)</h1>\n");
sb.append("Should redirect to " + location + "\n");
sb.append("</body></html>\n");
return sb.toString();
}
}
}

The latter is for sure the better solution regarding transparency and in our case necessary because we have to redirect to CAS which would not be possible with the former.


Friday, February 03, 2012

CentOS: Bind multiple IP-Adresses to a Network Interface

First thing is to define a single IP address for your host.

1) CentOS(RedHat) uses the file /etc/sysconfig/network to read the saved hostname at system boot. This is set using the init script /etc/rc.d/rc.sysinit
GATEWAY=192.168.0.254
HOSTNAME=www.mydomain.it
NETWORKING=yes
FORWARD_IPV6=yes
2) We define the nameserver for this system /etc/resolv.conf
search mydomain.it
nameserver 10.10.14.1
nameserver 10.10.14.2
3) Locally resolve node names to IP addresses /etc/hosts
127.0.0.1       localhost.localdomain   localhost       name        name.mydomain.it
::1             localhost6.localdomain6 localhost6      name        name.mydomain.it

16.18.24.241     name.mydomain.it          name
16.18.24.244     name.mydomain.it          name
4) Define the first ethernet connector /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
ONBOOT=yes
USERCTL=no
BOOTPROTO=none
NETMASK=255.255.255.128
IPADDR=192.168.0.241
PEERDNS=no

check_link_down() {
    return 1;
}
TYPE=Ethernet
IPV6INIT=no
5) Copy this configuration file to a virtual one, which could be for example eth0:0
cp ifcfg-eth0 ifcfg-eth0:0
6) And than change the settings in the newly created file /etc/sysconfig/network-scripts/ifcfg-eth0:0
DEVICE=eth0:0
ONBOOT=yes
USERCTL=no
BOOTPROTO=none
NETMASK=255.255.255.128
IPADDR=192.168.0.242
PEERDNS=no

check_link_down() {
    return 1;
}
TYPE=Ethernet
IPV6INIT=no
7) Restart the network to put it to work
service network restart

Tuesday, January 24, 2012

Single Sign On with CAS

There are a lot of different solutions in the market to solve this problem under which KErberos, OpenID, OAuth and of course JA-SIG CAS (Central Authentication Service)

The latter is used mainly in University environments, however it can be used in a lot of different environments as there exist integration for Java, PHP, ...

The following picture in my opinion shows best how the transitions between the three actors are defined


It all starts with a request from a user that wants to access a page on an application server (black arrow). As it is not yet known by the application the browser gets redirected to the CAS-server where the App.Server adds its service-id (usually the url of the web application). (red arrows)

this results in an URL like https://www.cas-server.xyz/cas/login?service=http://www.application-server.xyz/webapp

On this site the login screen of the CAS-server is shown and the user has to enter its credentials. The CAS-server generates the Ticket-Granting-Ticket (and a Cookie). The TGT is then sent back to the application (blue arrows).

Using this TGT the application cas contact the CAS-server to obtain a Service Ticket, which contains attributes and ids which are needed to authorise the user within the application (green arrows).

Ususally the ST is valid only for a single request but using the TGT the Application server can create multiple STs as long as the TGT is valid

Once authenticated at the CAS server the step of entering the credentials will be omitted (otherwise it wouldn't be SSO

Wednesday, January 18, 2012

Wireless Client (Bridge)

If you go into a TV-store these days you'll recognize that most of the newer models are equipped with some sort of "Smart-TV" facility. To use this feature you'll need to connect it to the internet which is possible via LAN or WLAN. The latter in my case was only possible by buying an original WLAN-adapter costing more than 50€.

Unfortunately at my home there is no possibility to use the LAN without restructuring the whole house and the adapter despite the high price is not really an option because it would be the third device (TV, Receiver, Apple-TV) in that furniture that would be wireless connected.

The possible solutions that came in my mind where two (three if opening the walls for new cables would be an option ;-)
Despite that powerline would be a very simple option without polluting the air with more electromagnetic waves it has some drawbacks. It depends highly on an uninterrupted connection between the sender and receiver, it is limited by the capabilities of the power line and its components are still very expensive.

The wireless bridge instead bundles all the different wireless connections into one and shares it through the wireless ports which is supported by most of the cheapest routers. Therefore it was the favorite choice to solve my problem.

After some investigation I found out that for example the "TP-Link TL-WR841N" can be configured as a wireless bridge and it was available below 35€

The advantage of this router is that it is compatible with "DD-WRT" which is an open source linux based operating system for routers, switches and so on. So after a short functioning test with the original firmware I just flashed it with this one (I think this change is reversible, but I'm not 100% sure)

The settings to change are described best in this article, so I'm not going to repeat them.

The whole setup took less than half an hour and is doable even for beginners, so unleash you router

UPDATE:
Actually the problem with this configuration is, that the devices in room2 do not see the devices in room1 and vice versa. This can be fixed with static routes.
And the real client bridge is not possible yet with this router

Thursday, January 12, 2012

Migrate to Hibernate 4 and Spring 3.1 - SessionFactory

As most of you probably have to do these days or in the near future we have to migrate our project to the newest Versions ob Hibernate and Spring. Actually the Version numbers are
  • Hibernate 4.0.0.Final
  • Hibernate Search 4.0.0.Final
  • Spring 3.1.0.RELEASE
If you want to perform a complete migration you'll need to change also to Spring 3.1. because in that version they added support for hibernate 4. For example they added the package
org.springframework.orm.hibernate4
which is needed for example to create the org.springframework.orm.hibernate4.LocalSessionFactoryBean which defines all the annotated classes and the hibernate properties needed to create the session

<!-- Hibernate SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="dataSource">
<property name="annotatedClasses">
<list>
<value>org.something.myClass</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.connection.driver_class=${hibernate.connection.driver_class}
hibernate.connection.url=${hibernate.connection.url}
hibernate.connection.username=${hibernate.connection.username}
hibernate.connection.password=${hibernate.connection.password}
hibernate.default_schema=${hibernate.default_schema}
hibernate.hbm2ddl.auto=${hibernate.hbm2ddl.auto}
hibernate.jdbc.batch_size=${hibernate.jdbc.batch_size}
hibernate.c3p0.max_size=${hibernate.c3p0.max_size}
hibernate.c3p0.min_size=${hibernate.c3p0.min_size}
hibernate.c3p0.timeout=${hibernate.c3p0.timeout}
hibernate.c3p0.max_statements=${hibernate.c3p0.max_statements}
hibernate.c3p0.idle_test_period=${hibernate.c3p0.idle_test_period}
hibernate.c3p0.acquire_increment=${hibernate.c3p0.acquire_increment}
hibernate.c3p0.validate=${hibernate.c3p0.validate}
hibernate.cache.region.factory_class=${hibernate.cache.region.factory_class}
hibernate.connection.provider_class=${hibernate.connection.provider_class}
hibernate.show_sql=${hibernate.show_sql}
hibernate.generate_statistics=${hibernate.generate_statistics}
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
</value>
</property>
</bean>
As you can see there is no definition of  eventlisteners whatsoever. Before version 3.6 of hibernate-search the changelisteners where defined here, which is now obsolete.

<!-- Obsolete in 3.6: FullTextIndexEventListener default constructor is obsolete. Remove all explicitevent listener configuration. As of Hibernate Core 3.6 Hibernate Search will be automatically enabled if it is detectedon the classpath.
<property name="eventListeners">  
<map>
<entry key="post-update">
<bean class="org.hibernate.search.event.FullTextIndexEventListener" />
</entry>
<entry key="post-insert">
<bean class="org.hibernate.search.event.FullTextIndexEventListener" />
</entry>
<entry key="post-delete">
<bean class="org.hibernate.search.event.FullTextIndexEventListener" />
</entry>
</map>
</property>-->
Another interesting change is that the class definition not just changed from hibernate3 to hibernate4 but in our case from org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean into org.springframework.orm.hibernate4.LocalSessionFactoryBean.
This leads to the lost of the possibility of defining a lobHandler which according to the JavaDoc of the LobHandler interface is still a good practice. I asked about this at stackoverflow, but I didn't got an answer yet, so I asked it today on the spring forum.


Furthermore you notice that now the complete connection properties including the c3p0 (cache) definition is defined in this bean. This makes it much simpler because there is no additional "datastore" bean needs to be there.
However there is still a "datastore" bean which needs to be defined otherwise you'll get a NullPointerException. (UPDATE: This will apparently be fixed in Spring 3.1.1)


Another important thing that needs to be defined in this bean is the hibernate-search. It's properties changed slightly in version 4.0 and the most important ones are shown below.
hibernate.search.lucene_version=${hibernate.search.lucene_version}
hibernate.search.analyzer=${hibernate.search.analyzer}
hibernate.search.default.directory_provider=${hibernate.search.default.directory_provider}
hibernate.search.default.filesystem_access_type=${hibernate.search.default.filesystem_access_type}
hibernate.search.default.locking_strategy=${hibernate.search.default.locking_strategy}
hibernate.search.default.indexBase=${hibernate.search.default.indexBase}
hibernate.search.default.indexmanager=${hibernate.search.default.indexmanager}
hibernate.search.default.refresh=${hibernate.search.default.refresh}
hibernate.search.default.reader.strategy=${hibernate.search.default.reader.strategy}
The real values of the properties depend highly on your environment, however if you need my values just drop me a comment and I'll add them.

UPDATE:
Unfortunately there is still an Error in hibernate 4.0.0.Final regarding the progress monitor when re-indexing the whole database. It seems that this error was found in CR1then fixed in CR2 and reappeared in the final version

Wednesday, January 04, 2012

Apple TV Untethered Jailbreak iOS5 (4.4.4)

Finally it is possible to update the Apple TVs to the newest version. Of course I know that it was possible since  Apple released it, however in my case the un-jailbreaked Apple TV is not really useful.

The problem is that I'm living in a region close to the border of my country and the official state language is not my mother tongue. Unfortunately you can not borrow multilingual movies in the iTunes store, so already the main functionality of the ATV is quite useless for me.

Despite that I don't care about that particular feature the ATV is really great, and if you jailbreak it, it is even better. Airplay works incomparably well between iDevices and sharing your iTunes libraries is perfekt for data that is used very often such as the music on your disc. If you want more I'll suggest to install nitoTV, XBMC and IceFilms.

Jailbreak:
What can I say to jailbreaking... At the end it is really straight forward and described best on the firecore webpage where you can also download the jailbreak-program.

What you need is:


Now just update your ATV to the latest Version using iTunes(to test if everything works well with the original Version) and jailbreak it using the instruction on the  firecore webpage.

Now we need to avoid that ATV updates its OS which would mean that all changes are lost we need to change the /etc/hosts file as follows; First backup the original file
cp /etc/hosts /etc/hosts.bak
Redirect the update sites to localhost, which means that there is no chance to ever find an update
echo "127.0.0.1 appldnld.apple.com" >> /etc/hosts
echo "127.0.0.1 mesu.apple.com" >> /etc/hosts
echo "127.0.0.1 appldnld.apple.com.edgesuite.net" >> /etc/hosts
This changes can be removed as follows (if you need to) or use the backup
sed -i '/127.0.0.1 appldnld.apple.com/d' /etc/hosts
sed -i '/127.0.0.1 mesu.apple.com/d' /etc/hosts
sed -i '/127.0.0.1 appldnld.apple.com.edgesuite.net/d' /etc/hosts
UPDATE: In the actual jailbreak the /etc/hosts is changed already by the jailbreak

Install nitoTV:
On Mac its simple, just open a terminal whereas on windows you'll need to download PuTTY. Now just connect to your ATV via openSSL.

  1. SSH into your ATV (e.g.ssh root@atv.ip  with default password “alpine”)
  2. passwd” to enter a new password (if you want to)
  3. echo “deb http://apt.awkwardtv.org ./” > /etc/apt/sources.list.d/awkwardtv.list
  4. apt-get update
  5. apt-get install com.nito.nitoTV
  6. killall Lowtide

Now after the restart you should have nitoTV installed and see it on the main ATV page.


Install XBMC:
That's even simpler; Within nitoTV there is one package in the list called XBMC-ATV2. Just istall that one and your done!


Install IceFilms:
IceFilms is a nice AddOn for XBMC that needs to be installed via SFTP.
1) Download the file (make sure that it remains .zip)
Then you'll need a program to send files to the ATV which for Windows can be WinSCP. Despite that the MAC is SSL-friendly there exists a simple GUI program for doing this which is CyberDuck
2) Sent the file via SFTP (default port 22) to the ATV in folder /private/var/mobile/Media folder
3) Open XBMC
4) Go to System --> AddOns
5) "Install from ZIP file" and go to the folder where you put the Zip and install it


Now the AddOn is installed and you can find it in the list of the Videos --> AddOns


Now that you have everything you need just enjoy your ATV2+ :-D