mercoledì 30 settembre 2009

Sistema Operativo Android , utilizzo del database SQLite

Il sistema operativo Android è molto avanzato, quasi simile a quello di un normale pc.
Si basa sul kernel Linux 2.6 e permette di sviluppare applicazioni java di alta complessità.
Al contrario di altri sistemi operativi (per telefoni), Android può utilizzare per la persistenza dei dati il database SQLite.

Esempio di un gerenic Dao Per Android

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class GenericDAO extends SQLiteOpenHelper {

private static final String TAG = "GenericDAO";
private static SQLiteDatabase db;
private static String dName;
private static String tName;
private static String sql;
public static final String KEY_ID = "_id";

private static GenericDAO instance;

private GenericDAO(Context ctx, String dbName, String sql, String tableName, int ver){
super(ctx, dbName, null, ver);
Log.i(TAG, "Creating or opening database [ " + dbName + " ].");
GenericDAO.sql = sql;
dName = dbName;
tName = tableName;
}

public static GenericDAO getInstance(Context ctx, String dbName, String sql, String tableName, int ver){
if(instance == null){
instance = new GenericDAO(ctx, dbName, sql, tableName, ver);
try{
Log.i(TAG, "Creating or opening the database [ " + dbName + " ].");
db = instance.getWritableDatabase();
}catch(SQLiteException se){
Log.e(TAG, "Cound not create and/or open the database [ " + dbName + " ] that will be used for reading and writing.", se);
}
}
return instance;
}

public void close(){
if(instance != null){
Log.i(TAG, "Closing the database [ " + dName + " ].");
db.close();
instance = null;
}
}

@Override
public void onCreate(SQLiteDatabase db){
Log.i(TAG, "Trying to create database table if it isn't existed [ " + sql + " ].");
try{
db.execSQL(sql);
}catch(SQLException se){
Log.e(TAG, "Cound not create the database table according to the SQL statement [ " + sql + " ].", se);
}
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
Log.i(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
try{
db.execSQL("DROP TABLE IF EXISTS " + tName);
}catch(SQLException se){
Log.e(TAG, "Cound not drop the database table [ " + tName + " ].", se);
}
onCreate(db);
}

public long insert(String table, ContentValues values){
return db.insert(table, null, values);
}

public Cursor get(String table, String[] columns){
return db.query(table, columns, null, null, null, null, null);
}

public Cursor get(String table, String[] columns, long id){
Cursor cursor =db.query(true, table, columns, KEY_ID + "=" + id, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}

public int delete(String table) {
return db.delete(table, "1", null);
}

public int delete(String table, long id) {
return db.delete(table, KEY_ID + "=" + id, null);
}

public int update(String table, long id, ContentValues values) {
return db.update(table, values, KEY_ID + "=" + id, null);
}
}



Modello java Notes.java
public class Notes {

public static final String DATABASE_NAME = "data";
public static final String DATABASE_TABLE = "notes";
public static final int DATABASE_VERSION = 1;
public static final String TABLE_CREATE =
"create table notes (_id integer primary key autoincrement, "
+ "title text not null, body text not null);";

public static final String COL_TITLE = "title";
public static final String COL_BODY = "body";

private int id;
private String title;
private String body;

public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getBody() {
return body;
}
public void setId(int id) {
this.id = id;
}
public void setTitle(String title) {
this.title = title;
}
public void setBody(String body) {
this.body = body;
}


}



Utilizzo del Dao
private String testCRUD(){

String result="";
Cursor cursor = null;
String[] columns = new String[] {GenericDAO.KEY_ID, Notes.COL_TITLE, Notes.COL_BODY};

GenericDAO dao = GenericDAO.getInstance(this, Notes.DATABASE_NAME, Notes.TABLE_CREATE, Notes.DATABASE_TABLE, Notes.DATABASE_VERSION);

if(dao != null){

ContentValues values = new ContentValues();
values.put(Notes.COL_TITLE, "aaa");
values.put(Notes.COL_BODY, "bbb");
dao.insert(Notes.DATABASE_TABLE, values);

values = new ContentValues();
values.put(Notes.COL_TITLE, "ccc");
values.put(Notes.COL_BODY, "ddd");
dao.insert(Notes.DATABASE_TABLE, values);

cursor = dao.get(Notes.DATABASE_TABLE, columns);


int idColumn = cursor.getColumnIndex(GenericDAO.KEY_ID); 
int titleColumn = cursor.getColumnIndex(Notes.COL_TITLE); 
int bodyColumn = cursor.getColumnIndex(Notes.COL_BODY); 
.....................................................................
.....................................................................
.....................................................................
result += " now update the second record.";

values = new ContentValues();
values.put(Notes.COL_TITLE, "eee");
values.put(Notes.COL_BODY, "fff");
dao.update(Notes.DATABASE_TABLE, 2, values);

cursor.requery();
cursor.close();

result += " now delete first record.";

dao.delete(Notes.DATABASE_TABLE, 1);

result += " now delete all records.";

dao.delete(Notes.DATABASE_TABLE);

dao.close();
}

return result;

}

Android mette a disposizione dei programmatori librerie, tutorial, esempi di codice e un plugin per Eclipse.
Quest'ultimo è stato scelto da Google come ambiente di sviluppo ufficiale.

martedì 29 settembre 2009

Istanziare classi annidate con Spring

Tra le varie possibilità offerte da Spring di istanziare un oggetto non poteva mancare l'istanziazione delle classi annidate.
Ipotizziamo di avere una classe IndexArgsFactory definita all'interno di IndexArgs:
public final class IndexArgs
{

    public static final class IndexArgsFactory
    {

        public IndexArgsFactory(FormulaManager formulaManager)
        {
          // [...]
        }
    }
    // [...]
}
Nel file di configurazione di Spring dovremo usare la notazione:
<bean id="indexArgsFactory" class="it.sinossi.example.IndexArgs$IndexArgsFactory">
  <constructor-arg ref="formulaManager" />
</bean>
Dove il carattere "$" fa da separatore tra la classe contenitore e la classe annidata.

Vedi anche:
Nested Classes
Inner classes
[LINK] I Layout di SWT
Su Eclipse Corner Article, un articolo piuttosto approfondito che svela molte delle caratteristiche dei layout di SWT.

Understanding Layouts in SWT..


venerdì 25 settembre 2009

Il cestino di Oracle

A partire dalla versione 10g nel database Oracle è stato introdotto il concetto di cestino (Recycle Bin), il cui funzionamento è analogo a quello del cestino presente nei sistemi operativi: le tabelle droppate non vengono immediatamente rimosse dal database ma vanno invece a finire nella Recycle Bin, da cui possono poi eventualmente recuperate senza grosse difficoltà.

Le tabelle droppate non vengono cancellate ma rinominate (insieme a tutti gli oggetti collegati come indici, trigger, ...) con dei nomi generati dal sistema che cominciano per BIN$.

Per visualizzare le tabelle droppate presenti nella Recycle Bin:
select * from recyclebin;

Per ripristinare una tabella precedentemente droppata:
flashback table DROPPED_TABLE_NAME to before drop;

Per svuotare la Recycle Bin:
purge recyclebin;

Per eliminare definitivamente una tabella senza passare per la Recycle Bin:
drop table TABLE_NAME purge;

La Recycle Bin può essere abilitata/disabilitata:
alter session set recyclebin = on;
alter session set recyclebin = off;

lunedì 21 settembre 2009

Recuperare i nomi dei mesi/giorni nelle varie localizzazioni

Le localizzazioni delle stringhe relative alle date sono gestite dalla classe DateFormatSymbols.
Tramite metodi come getMonths o getWeekdays è possibile recuperare i valori che vengono poi utilizzati nella formattazione delle date.

DateFormatSymbols dfs = new DateFormatSymbols(Locale.ITALIAN);
String[] monthNames = dfs.getMonths();
for (String month : monthNames) {
 System.out.println(month);
}

L'output sarà:
gennaio
febbraio
marzo
aprile
maggio
giugno
luglio
agosto
settembre
ottobre
novembre
dicembre

Si deve fare particolare attenzione alle lettere maiuscole/minuscole delle stringhe restituite, che seguiranno la convenzione della lingua selezionata. Ad esempio in italiano i nomi dei mesi e dei giorni sono dei nomi comuni ed hanno l'iniziale minuscola (gennaio, febbraio, ...) mentre in inglese i nomi iniziano con la lettera maiuscola (January, February, ...).

Un'altra particolarità, dovuta alle stranezze della classe Calendar, sono gli array di stringhe restituiti: nel caso dei mesi l'array ha 12 elementi che hanno indici da 0 a 11; nel caso dei giorni della settimana invece l'array ha 8 elementi, con il primo elemento, quello con indice 0, contenente una stringa vuota, gli elementi successivi contengono i nomi dei giorni della settimana, a partire dalla domenica.
Qual è la causa di questa anomalia?
Questi array vengono acceduti utilizzando come indici le costanti della classe Calendar, quindi l'anomalia dell'array dei nomi dei giorni è dovuta al fatto che mentre le costanti che rappresentano i mesi partono da 0 (Calendar.JANUARY == 0), le costanti che identificano i giorni della settimana partono da 1 (Calendar.SUNDAY == 1).

DateFormatSymbols dfs = new DateFormatSymbols(Locale.ITALIAN);
String[] weekdays = dfs.getWeekdays();
for (int i = 0; i < weekdays.length; i++) {
 System.out.println(i + " " + weekdays[i]);
}
Visualizza
0 
1 domenica
2 lunedì
3 martedì
4 mercoledì
5 giovedì
6 venerdì
7 sabato

Vedi anche:
DateFormatSymbols

venerdì 18 settembre 2009

Come deprecare un metodo

Quando si vuole eliminare un metodo da una classe, evitando di interferire sul codice che da questa dipende, la soluzione sta nella deprecazione.
Dalla versione 1.5 di Java per deprecare un metodo si deve usare l'annotazione @Deprecated, che può essere usata sulle classi, sui metodi o sui campi.
E' buona norma accompagnare l'annotazione con i javadoc, usando il tag @deprecated nel cui testo è opportuno specificare perchè il metodo viene deprecato e qual è l'alternativa da utilizzare.


/**
* [...]
* @deprecated use {@link #importTrade(Trade)} instead ...
*/
@Deprecated
Long importTradeFromXML(String xml) {
...


Per creare nei javadoc un collegamento ad un altro metodo viene utilizzato il tag @link la cui sintassi è:

{@link package.class#member label}

Nel caso di overloading dei metodi si deve specificare il metodo facendo seguire al nome l'elenco dei tipi degli argomenti presi in ingresso.

Vedi anche:
How and When To Deprecate APIs
javadoc @deprecated
javadoc @link

giovedì 17 settembre 2009

[Link] Back to the basics: Display, Shell, Window ...

Un articolo interessante su alcuni aspetti (a volte oscuri) di Eclipse RCP:

Back to the basics: Display, Shell, Window ...

marco