Latest Entries »

Monday, March 12, 2012

JavaServer Faces website navigation map with Primefaces


Introduction


Hello. In this article I will show you how to create a simple website navigation map like those in asp.net (web.sitemap) which contains reference to your pages. Composite Component of navigation path will be localized on many languages and will be build on PrimeFaces BreadCrumb component. Final result will look like this:

Using PrimeFaces

Configuring PrimeFaces is as easy as riding a bike so I ommit this topic.
I'll create JSF 2.0 Composite Component with BreadCrumb inside and point it's dynamic model to ManagedBean which will use our newly created CC component.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:p="http://primefaces.org/ui">

  <!-- INTERFACE -->
  <cc:interface>
      <cc:attribute name="model" required="true" />
      <cc:attribute name="styleClass" required="false" />
      <cc:attribute name="style" required="false" />
  </cc:interface>

  <!-- IMPLEMENTATION -->
  <cc:implementation>
      <p:breadCrumb styleClass="#{cc.attrs.styleClass}" style="#{cc.attrs.style}" model="#{cc.attrs.model}">
        </p:breadCrumb>
  </cc:implementation>
</html>

Implementing code for receive pages in project


Now it's time for ManagedBean holding all data. Most significant piece of code from class below is localized in public getWebsites(). Firstly I load localized messages and load filenames from root path "/". Next step is checking whether filename exists in localized messages:

package com.blogspot.rpiesnikowski.root;

import java.io.File;
import java.lang.String;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.faces.component.UIForm;
import javax.faces.component.UIViewRoot;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FileUtils;
import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;

/**
 *
 * @author rpiesnikowski
 */
@Named(value = "template")
@RequestScoped
public class TemplateBean {
    private MenuModel websites;

    /**
     * Method for dynamically create navigation for all pages inside
     * root directory.
     * @return
     */
    public MenuModel getWebsites() {
  // Receiving i18n bundle messages 
        String bundleName = "locales.messages";
        String Name = "";
        Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
        ResourceBundle bundle = ResourceBundle.getBundle(bundleName, locale);
        websites = new DefaultMenuModel();
        HttpServletRequest req =  (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        // Getting all files for path and then using Apache Commons 
  String rootPath = req.getServletContext().getRealPath("/");
        Collection<File> files = FileUtils.listFiles(new File(rootPath),new String[]{"xhtml"}, false);
        websites.addMenuItem(createMenuItem("#", "#"));
        for (File f: files){
            Name = f.getName().replace(".xhtml", "");
   // Checking if localized messages has key 
            if(bundle.containsKey(Name))
                websites.addMenuItem(createMenuItem(bundle.getString(Name), f.getName().replace(".xhtml", ".jsf")));
        }
        return websites;
    }

    public void setWebsites(MenuModel websites) {
        this.websites = websites;
    }

    protected MenuItem createMenuItem(String Name, String Url) {
        MenuItem item = new MenuItem();
        item.setValue(Name);
        item.setUrl(Url);
        return item;
    }
 
    public TemplateBean() {
    }
}

Now it's time to use component somewhere in Facelets Template:

<sc:NavigationPath model="${template.websites}" style="width: 99%;" />

Localizing NavigationPath Last but not least thing is to add localization files and modify your faces-config.xml. Put this between application node:

<application>
 <locale-config>
  <default-locale>en-US</default-locale>
  <supported-locale>pl</supported-locale>
  <supported-locale>fr</supported-locale>
  <supported-locale>es</supported-locale>
 </locale-config>
 <resource-bundle>
  <base-name>locales.messages</base-name>
  <var>msgs</var>
 </resource-bundle>
</application>

And it's time for localized message:

Calendar=Calendard a'la France
AjaxEngine=AjaxEngine a'la France
index=Index a'la France
DummyPage=DummyPage a'la France
BreadCrumb=BreadCrumb a'a France
asdf=asdf a'la France
ClientIdExample=ClientId a'la France

Additional tip

I've found really nice trick when I put my all empty localized messages into project. Try right click over messages.properties and choose Open. You this nice GUI form for filling localized strings.

Saturday, January 14, 2012

jQuery check if element has border

Sometimes you need to check if an html element has border for some reason. Normally we can use build in function css() for this purpose. But this approach is quite troublesome to find answer due to some facts: $(element).css('property') function returns window.getComputedStyle(element) . For border we have 4 css-computed rules:

.someClass{
    border: 1px solid black;
    /* is in fact computed in browser as */
    border-top-style: solid;
    border-right-style: solid;
    border-bottom-style: solid;
    border-left-style: solid;
}

To check if element has border we need to write something like this. Code is simple but in fact really ugly.

if ($(element).css('border-top-style') != 'none' && 
        $(element).css('border-right-style') != 'none' &&
        $(element).css('border-bottom-style') != 'none' &&
        $(element).css('border-left-style') != 'none'){
    //Has border
    }

Moreover code above may give you wrong result. Imagine situation when web-developer wrote:

.anotherFancyClass{
    /* only bottom border */
    border-bottom: 1px solid black;
    /* is in fact computed as */
    border-top-style: none;
    border-right-style: none;
    border-bottom-style: solid;
    border-left-style: none;
}

Now javascript if condition fail. You can change condition from AND to OR but it is still UGLY code.

Better solution


To check if element has border we will use another functions:

And here's a code and explaination:


$.fn.hasBorder = function() {
    /* outer contains: dimensions + padding + border */
    /* inner contains: dimensions + padding */
  if ((this.outerWidth() - this.innerWidth() > 0) ||  (this.outerHeight() - this.innerHeight() > 0)){
        return true;
    }
    else{
        return false;
    }
  };
  
  /* Usage */
  if ($('#selector').hasBorder()){
      //With border. Such more sophisticated ain't true?
  }

That's all.

Thursday, January 12, 2012

Android service with dynamic schedule time

Introduction

In this article I will show you how to write example android service which will be restarted after change user preferences. After changes are applied service will show toast with last execution time.


XML Files

First we will write some piece of code that will display preferences and will show them to user. Let's start from define xml with preferences:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <PreferenceCategory android:title="Update frequency" >
        <ListPreference
            android:defaultValue="15 minut"
            android:entries="@array/listFrequency"
            android:entryValues="@array/listValues"
            android:key="Frequency"
            android:title="Change update frequency" />
    </PreferenceCategory>

</PreferenceScreen>

Here goes entries and entryValues from @array:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="listFrequency">
        <item>1 minuta</item>
        <item>2 minuty</item>
        <item>10 minut</item>
        <item>15 minut</item>
        <item>30 minut</item>
        <item>Wylaczone</item>
    </string-array>
    <string-array name="listValues">
        <item>60000</item>
        <item>120000</item>
        <item>600000</item>
        <item>900000</item>
        <item>1800000</item>
        <item>0000</item>
    </string-array>
</resources>

This xml will look like:

And don't forget to modify AndroidManifest.xml
<application>
     .....
        <service
            android:enabled="true"
            android:name=".service.BackgroundService" >
        </service>
    </application>
 <uses-permission android:name="android.permission.VIBRATE" />

Now let's code.

It's time to create Activity which will extend PreferenceActivity class. In this class we add OnSharedPreferenceChangeListener which will be called after change user preferences.
package com.stock_app.home;

import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.widget.Toast;

import com.stock_app.R;
import com.stock_app.service.BackgroundService;

public class PreferencesActivity extends PreferenceActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  addPreferencesFromResource(R.xml.preferences);
  SharedPreferences prefs = PreferenceManager
    .getDefaultSharedPreferences(this);
  prefs.registerOnSharedPreferenceChangeListener(prefchanged);
 }

 OnSharedPreferenceChangeListener prefchanged = new OnSharedPreferenceChangeListener() {

  @Override
  // Method for listening changes of SharedPreferences. 
  public void onSharedPreferenceChanged(
    SharedPreferences sharedPreferences, String key) {
   Intent serviceIntent = new Intent(getBaseContext(),
     BackgroundService.class);
   // Only if key was Frequency we will restart service. 
   if (key.equals("Frequency")) {
    String value = sharedPreferences.getString("Frequency", "0000");
    // If user turned of Service 
    if (value.equals("0000")) {
     stop(serviceIntent);
     String message = "Service is shut down.";
     Toast myToast = Toast.makeText(getApplicationContext(),
       message, Toast.LENGTH_SHORT);
     myToast.show();

    } else {
     // Oherwise restart
     stop(serviceIntent);
     start(serviceIntent);
    }

   }
  }
 };
 // Helper methods for start/stop service 
 private void start(Intent serviceIntent) {
  try {
   startService(serviceIntent);
  } catch (Exception e) {
   // If exception thrown means service is running 
   stopService(serviceIntent);
  }
 }

 private void stop(Intent serviceIntent) {
  try {
   stopService(serviceIntent);
  } catch (Exception e) {
   // If exception thrown means service not is running 
   startService(serviceIntent);
  }
 }
}

Now it's time for Service:

package com.stock_app.service;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

public class BackgroundService extends Service {

 private static final String TAG = BackgroundService.class.getSimpleName();
 private static int NOTIFICATION_ID = 1;
 private int icon = (Integer) 0x7f02000d;
 private Toast myToast;

 private Timer updatingTimer;
 public NotificationManager notificationmanager;
 public static boolean isGoing = false;
 SharedPreferences preferences = null;
 private TimerTask notify;

 @Override
 public void onCreate() {
  super.onCreate();

  if (!isGoing) {
   notify = new TimerTask() {
    @Override
    public void run() {
     checkValues();
    }
   };
   notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
   updatingTimer = new Timer();
  }

 }

 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }

 @Override
 public void onDestroy() {
  updatingTimer.cancel();
  notify.cancel();
  super.onDestroy();
  isGoing = false;
 }

 public void onStart(Intent intent, int startId) {
  super.onStart(intent, startId);
  String message = "";
  isGoing = true;
  preferences = PreferenceManager.getDefaultSharedPreferences(this);
  try {

   String str_frequency = preferences
     .getString("Frequency", "1800000");
   long frequency = Long.parseLong(str_frequency);

   if (str_frequency.equals("60000")) {
    message = "Changed to one minute";

   } else if (str_frequency.equals("120000")) {
    message = "Changed to 2 minutes";
   } else if (str_frequency.equals("600000")) {
    message = "Changed to 10 minutes";

   } else if (str_frequency.equals("900000")) {
    message = "Changed to 15 minutes";

   } else if (str_frequency.equals("1800000")) {
    message = "Changed to 30 minutes";
   }

   // If running show toast:
   if (message != "" && message != "0000") {
    myToast = Toast.makeText(getApplicationContext(), message,
      Toast.LENGTH_SHORT);
    myToast.show();
   }

   updatingTimer.scheduleAtFixedRate(notify, 1 * 1000, frequency);
  } catch (Exception ex) {
   Log.i(TAG, ex.toString());
  }
 }

 public void displayNotificationMessage(String message) {
  Notification notif = new Notification(icon, message,
    System.currentTimeMillis());

  // enabling vibrate
  boolean checkVibration = preferences
    .getBoolean("checkVibration", false);
  if (checkVibration)
   vibrtationEnabled(notif);

  // enabling sound
  boolean checkSound = preferences.getBoolean("checkSound", false);
  if (checkSound)
   soundEnabled(notif);

  PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
    new Intent(this, BackgroundServiceActivity.class), 0);

  notif.setLatestEventInfo(this, "Notification!", message, contentIntent);
  notif.defaults |= Notification.DEFAULT_LIGHTS;
  notificationmanager.notify(NOTIFICATION_ID, notif);
  NOTIFICATION_ID++;
 }

 public void vibrtationEnabled(Notification notification) {
  long[] vibrate = { 0, 100, 200, 300 };
  Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
  vibrator.vibrate(vibrate, -1);

 }

 public static void soundEnabled(Notification notification) {
  notification.sound = Uri
    .parse("android.resource://com.stock.app/raw/notifsound");
  notification.defaults |= Notification.DEFAULT_SOUND;

 }

 public void checkValues() {
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");
  Calendar c = Calendar.getInstance();
  c.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH,
    Calendar.HOUR, Calendar.MINUTE, Calendar.SECOND);
  Date time = c.getTime();
  displayNotificationMessage(sdf.format(time));
 }
}


Conclusion

This is a sample code that will make your life easier :) If you want full application source code @me.

Tuesday, October 25, 2011

Android HTML parser in less than 5 minutes.

Yes it's true. You can create a simple application that parse a html document and get all data you need in less than 5 minutes.

Introduction

In this tutorial I will use standalone Java SE parser called Jsoup. We have few jsoup files available:

In android world size matter so I want only my jsoup-1.6.1-sources.jar. So far jar is an archive so I use 7-zip to extract content of  jsoup-1.6.1-sources.jar into folder. Next thing is to create Android Application from Eclipse IDE. 
After extracting sources from jsoup you should copy all directories inside your src folder. You should have similar application structure:




public class HtmlAParseActivity extends Activity {
 EditText text1;
 Button btn1;

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  text1 = (EditText) findViewById(R.id.editText1);
  btn1 = (Button) findViewById(R.id.button1);
  btn1.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    Document doc;
    try {
     doc = Jsoup.connect(text1.getText().toString()).get();
     Elements links = doc.select("a[href]");
     Elements media = doc.select("[src]");
     Elements imports = doc.select("link[href]");
     print("\nMedia: (%d)", media.size());
     for (Element src : media) {
      if (src.tagName().equals("img"))
       print(" * %s: <%s> %sx%s (%s)", src.tagName(),
         src.attr("abs:src"), src.attr("width"),
         src.attr("height"),
         trim(src.attr("alt"), 20));
      else
       print(" * %s: <%s>", src.tagName(),
         src.attr("abs:src"));
     }

     print("\nImports: (%d)", imports.size());
     for (Element link : imports) {
      print(" * %s <%s> (%s)", link.tagName(),
        link.attr("abs:href"), link.attr("rel"));
     }

     print("\nLinks: (%d)", links.size());
     for (Element link : links) {
      print(" * a: <%s>  (%s)", link.attr("abs:href"),
        trim(link.text(), 35));
     }
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

   }
  });
 }

 private static void print(String msg, Object... args) {
  System.out.println(String.format(msg, args));
 }

 private static String trim(String s, int width) {
  if (s.length() > width)
   return s.substring(0, width - 1) + ".";
  else
   return s;
 }
}
Of course don't forget to add permission for internet connection.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.persmission.ACCESS_NETWORK_STATE" />

Code in HtmlAParseActivity  was from org.jsoup.example package with some modifications.

Thats all.

Tuesday, September 27, 2011

Insert Update row with MERGE keyword SQL 2008

Few days ago I've got question how to perform insert/update taks in one query. I couldn't answer because I've never used MERGE in SQL 2008 Server. With my curiosity I make reaserch and google and found a solution. Furthermore almost all examples about MERGE was connected with two tables joining by PK-FK but I needed MERGE with one table. For show this query let first prepare a simple table:
CREATE TABLE [dbo].[Target](
	[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
	[EmployeeName] [nvarchar](500) NOT NULL,
 CONSTRAINT [PK_Target] PRIMARY KEY CLUSTERED 
(
	[EmployeeID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,
 ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Now It's time for write stored procedure that takes adventage of MERGE.

ALTER PROCEDURE [dbo].[TargetInsertUpdate]
(
   @EmployeeID INT,
   @EmployeeName NVARCHAR(500),
   @NewEmployeeID   int OUTPUT
)
AS
SET NOCOUNT ON


MERGE dbo.[Target]  T
-- To check if row is in database we put
-- existing row data inside USING (Source table )(S)
-- if row exists then name is updated
-- otherwise new row is added
-- and @NewEmployeeID indicates newly added ID
USING (SELECT @EmployeeID as EmployeeID,@EmployeeName as EmployeeName) as S
ON T.EmployeeID = S.EmployeeID
WHEN NOT MATCHED BY TARGET THEN
INSERT(EmployeeName) VALUES(S.EmployeeName)
WHEN MATCHED THEN
UPDATE SET T.EmployeeName = S.EmployeeName;

SET @NewEmployeeID = scope_identity()
GO