Posts Tagged Java
Delete the components holding unwanted state
This is a small addition to a problem discussed on the MyFaces Wiki: http://wiki.apache.org/myfaces/ClearInputComponents
Just in case the page is removed from the Wiki, please see below a copy of the problem description:
Sometimes you want to provide a command component (eg a link or button) that performs some server action, and renders the same page but with completely “fresh” values for all components.
When using command components with the normal immediate setting (false), achieving this is just a matter of clearing the beans that the JSF component value attributes access. Any values entered by the user will have been pushed into these beans as part of the Update Model phase, so the components themselves will not be holding any information about submitted data. The action method associated with the command is then run which resets the model, and when the components render themselves they will draw fresh data from the (reset) beans.
Note that because data is being pushed into the model, the validation phase must run, and therefore any invalid data in the page will cause the action to be skipped, and the page is redisplayed with the validation errors displayed. This is not generally the desired behaviour for a “clear” type operation! The solution is to set attribute immediate=true on the command so that its associated action is invoked before validation is applied to the input components in the same view (see How_The_Immediate_Attribute_Works).
However when using command components with immediate=true, things become more complex. All components will retrieve the raw submitted values submitted by the user, but the immediate command will then run before they can be pushed into the backing beans; the components therefore remember this data. When the (immediate) action causes navigation to another view then this is no problem; these components will be discarded anyway. However if the action method causes JSF to go directly to the render phase ‘of the same view’ [by calling facesContext.renderResponse()], then the components will behave as they do for a validation failure – by displaying the value cached in the component rather than fetching data from the backing bean.
MyFaces gave four solutions to this problem, but the one I used is the following:
Find the parent component of the problem inputs, and call
parentComponent.getChildren().clear();
During the render phase, new instances of these child components will then be created, while other components will not be affected.
This is effectively the same as the above solution, but discards a selected subset of components rather than the UI!ViewRoot.
Obtaining the parent component to discard can be done via binding. Alternatively, the “action listener” form of callback can be used for the command; this is passed an ActionEvent from which the command component that was clicked can be found. A call to “findComponent” can be made on this to locate the desired parent component by id, or other similar solutions.
All of this is good and well but what if you don’t have the component object but only the name of the form? How would you call the clear
method then?
This is the reason why I wrote the code below:
/** * Return the UIComponent that represents the root of the UIComponent tree. * @return the UIComponent that represents the root of the UIComponent tree */ public static UIViewRoot getUIViewRoot() { FacesContext facesContext = FacesContext.getCurrentInstance(); return facesContext != null ? facesContext.getViewRoot() : null; } /** * Search for a component in the UIComponent tree * @param parentComponent the parent component * @param componentId the component identifier we look for * @return the component found */ private static UIComponent findComponent(UIComponent parentComponent, String componentId) { if (parentComponent != null) { if (componentId.equals(parentComponent.getId())) { return parentComponent; } for (UIComponent child : parentComponent.getChildren()) { UIComponent component = findComponent(child, componentId); if (component != null) { return component; } } } return null; } /** * Deletes components holding unwanted state * @param componentId the component identifier */ public static void deleteComponentsHoldingUnwantedState(UIComponent parentComponent) { if (parentComponent != null) { parentComponent.getChildren().clear(); } } /** * Deletes components holding unwanted state * @param componentId the component identifier */ public static void deleteComponentsHoldingUnwantedState(String componentId) { deleteComponentsHoldingUnwantedState(findComponent(getUIViewRoot(), componentId)); }
The last method of the code above will allow you to delete all the components holding unwanted state of a form simply by passing its name.
For example:
deleteComponentsHoldingUnwantedState("myform");
JDBC and the “zero” date
A few weeks ago, I was in the process of writing a little script in Java to extract data from a MySQL database. Because this is what we can call a micro project, I decided to simply use JDBC to talk to the database.
But when I tried to run my script, I got the following exception:
java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Date at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:910) at com.mysql.jdbc.ResultSet.getDateFromString(ResultSet.java:2032) at com.mysql.jdbc.ResultSet.getDate(ResultSet.java:1956) at com.mysql.jdbc.ResultSet.getDate(ResultSet.java:1924) at com.mysql.jdbc.ResultSet.getDate(ResultSet.java:1972) ...
After looking at the database, it seems that this exception has been thrown because the fields of type datetime
contain the value ‘0000-00-00 00:00:00’. Don’t ask me why I have this kind of value in the database! Obviously, we would prefer to have a NULL
value instead of a “zero” date.
There are two solutions to fix this problem:
-
Replace all the “zero” dates by
NULL
using the following SQL query:UPDATE table SET datefield = NULL WHERE datefield = '0000-00-00 00:00:00';
-
Add the parameter
zeroDateTimeBehavior=convertToNull
to the connection url which will automatically convert the “zero” date toNULL
. Please find below an example of connection url with this parameter:jdbc:mysql://localhost:3306/dbname?zeroDateTimeBehavior=convertToNull
Personally, I choose the second solution as I didn’t want to change the original data of the database.
Update your Twitter status with Java
This article has been written for the version 2.1.7 of Twitter4J. If you want to use a newer version, please read the following article: Changes in Twitter4J 2.2.5
Some time ago, Twitter stopped supporting “Basic Authentication” in the Twitter API, in favour of a new, more secure system, OAuth.
Please read this article for more information about OAuth: http://en.wikipedia.org/wiki/OAuth
The basic authentication was straightforward, you only needed to provide the Twitter username and password in order to authenticate and send tweets from an application. That was it!
But things get more complicated with the new authentication. 🙁
You now need FOUR credentials:
- A consumer key;
- A consumer secret;
- An access token;
- An access token secret.
Please follow the instructions below to get these credentials for your application:
- Register the site as an application on http://dev.twitter.com/apps/new
- If you’re not currently logged in, use the Twitter username and password which you want associated with this site
- Your Application’s Name will be what shows up after “via” in your twitter stream. Your application name cannot include the word “Twitter.” I suggest using the name of your web site.
- Your Application Description can be whatever you want
- Application Type should be set on Browser
- The Callback URL should be the URL of your web application
- Default Access type must be set to Read & Write (this is NOT the default)
Once you have registered your site as an application, you will be provided with a consumer key and a consumer secret.
- Get the access token executing the following code:
import java.io.BufferedReader; import java.io.InputStreamReader; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; import twitter4j.http.AccessToken; import twitter4j.http.RequestToken; public class TwitterAccessToken { private static final String CONSUMER_KEY = "[your consumer key]"; private static final String CONSUMER_SECRET = "[you consumer secret]"; public static void main(String[] args) throws Exception { Twitter twitter = new TwitterFactory().getInstance(); twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET); RequestToken requestToken = twitter.getOAuthRequestToken(); AccessToken accessToken = null; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while (null == accessToken) { System.out.println("Open the following URL and grant access to your account:"); System.out.println(requestToken.getAuthorizationURL()); System.out.print("Enter the PIN (if available) or just hit enter.[PIN]:"); String pin = br.readLine(); try { if (pin.length() > 0) { accessToken = twitter.getOAuthAccessToken(requestToken, pin); } else { accessToken = twitter.getOAuthAccessToken(); } } catch (TwitterException e) { if (401 == e.getStatusCode()) { System.err.println("Unable to get the access token."); } else { e.printStackTrace(); } } } System.out.println("Access Token: " + accessToken.getToken()); System.out.println("Access Token Secret: " + accessToken.getTokenSecret()); } }
Once you have executed this script and followed the instructions, you will be provided with an access token and an access token secret.
Finally, here is the code to update your Twitter status using the new credentials:
import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; import twitter4j.conf.ConfigurationContext; import twitter4j.http.AccessToken; import twitter4j.http.OAuthAuthorization; public class TwitterTest { private static final String ACCESS_TOKEN = "[your access token]"; private static final String ACCESS_TOKEN_SECRET = "[your access token secret]"; private static final String CONSUMER_KEY = "[your consumer key]"; private static final String CONSUMER_SECRET = "[you consumer secret]"; public static void main(String[] args) { AccessToken accessToken = new AccessToken(ACCESS_TOKEN, ACCESS_TOKEN_SECRET); OAuthAuthorization authorization = new OAuthAuthorization(ConfigurationContext.getInstance(), CONSUMER_KEY, CONSUMER_SECRET, accessToken); Twitter twitter = new TwitterFactory().getInstance(authorization); try { twitter.updateStatus("Hello World!"); } catch (TwitterException e) { System.err.println("Error occurred while updating the status!"); return; } System.out.println("Successfully updated the status."); } }
Please note that this code is using the Java library Twitter4J which helps to integrate a Java application with the Twitter service.
Illegal Key Size
About a week ago, I wrote an article on how to encrypt with PHP and decrypt with Java. The funny thing is I got an error when I deployed the Java code into the live server! 😐
As a reminder, this is the code I am talking about:
SecretKeySpec skeySpec = new SecretKeySpec("SECRET KEY".getBytes(), "AES"); IvParameterSpec initalVector = new IvParameterSpec("iv_example".getBytes()); Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, initalVector);
This code was working perfectly fine on my local machine but here is the exception I got when I ran it on a Linux server:
java.security.InvalidKeyException: Illegal key size at javax.crypto.Cipher.a(DashoA12275) at javax.crypto.Cipher.a(DashoA12275) at javax.crypto.Cipher.a(DashoA12275) at javax.crypto.Cipher.init(DashoA12275) at javax.crypto.Cipher.init(DashoA12275) ...
Looking on internet for an explanation, I found the following answer on Charitha Kankanamge’s blog (which I slightly updated):
“java.security.InvalidKeyException: Illegal key size” error is a common issue which occurs when you try to invoke a secured web service in an environment where the provision for java unlimited security jurisdiction is not done.
This can be avoided by installing Java Cryptography Extension (JCE) unlimited strength jurisdiction policy files.
1. Go to http://www.oracle.com/technetwork/java/javase/downloads/index.html
2. Go to the Additional Resources section and click on the download button next to “Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files X”
3. Download jce_policy-X.zip and extract it into a directory
4. You will find local_policy.jar and US_export_policy.jar files there in the extracted directory. Copy these two files to $JAVA_HOME/jre/lib/security directory (These files might already be there, replace them in this case)
5. Restart the web server and invoke your secured service again. You will not encounter the “invalidkeyException” any more
Please click on the link below to see the original article:
http://charithaka.blogspot.com/2008/08/how-to-avoid-javasecurityinvalidkeyexce.html
Encrypt with PHP – Decrypt with Java
For security reason, I wanted to encrypt the data transferred between PHP web services and a Java application. But the problem was to encrypt the data with PHP in a way that it is possible to decrypt it using Java.
It obviously exists a lot of ways of doing this. But here is the way I choose:
- Use a secret key and an initialisation vector for the encryption and decryption
- Use the mcrypt PHP module for the encryption
- Use the javax.crypto Java package for the decryption
Please find below the PHP code for the encryption:
function encrypt($message, $initialVector, $secretKey) { return base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_128, md5($secretKey), $message, MCRYPT_MODE_CFB, $initialVector ) ); }
And please see below the Java code for the decryption:
public static String md5(String input) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] messageDigest = md.digest(input.getBytes()); BigInteger number = new BigInteger(1, messageDigest); return number.toString(16); } public String decrypt(String encryptedData, String initialVectorString, String secretKey) { String decryptedData = null; try { SecretKeySpec skeySpec = new SecretKeySpec(md5(secretKey).getBytes(), "AES"); IvParameterSpec initialVector = new IvParameterSpec(initialVectorString.getBytes()); Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, initialVector); byte[] encryptedByteArray = (new org.apache.commons.codec.binary.Base64()).decode(encryptedData.getBytes()); byte[] decryptedByteArray = cipher.doFinal(encryptedByteArray); decryptedData = new String(decryptedByteArray, "UTF8"); } catch (Exception e) { LOGGER.debug("Problem decrypting the data", e); } return decryptedData; }
EDIT: The line number.toString(16)
of the md5 method needs to be replaced by String.format("%032x", number)
. See this article for more details.