Archivi categoria: Java Programming

Gran parte della mia vita lavorativa riguarda Java..

Tomcat 7, jndi datasource ed eclipse

Piccola guida per la risoluzione di un banale task ma che spesso crea problemi, e cioè la definizione di un datasource jdbc su Tomcat .
Nel caso specifico utilizzo un datasource con driver SqlServer di Microsoft.
La libreria Microsoft contenente il driver jdbc (nel mio caso la sqljdbc4.jar), deve essere messa nella cartella lib del server tomcat.
Va poi configurata la risorsa jndi nel file server.xml nella cartella conf di tomcat, aggiungendo ad esempio questo :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--?xml version="1.0" encoding="UTF-8"?-->
<!--contenuto vario del nostro file server,trovare l'elemento globalnamingresources e aggiungere la nostra resource-->
<GlobalNamingResources>
<Resource name="jdbc/testdb" auth="Container" type="javax.sql.DataSource"
        username="kiraya"
        password="kiraya"
        factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"

        driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
        url="jdbc:sqlserver://xx.xx.xx.xx:1433;DatabaseName=MYDB"
        maxActive="50"
        maxIdle="10"
        maxWait="15000"
        removeAbandoned="true"
       removeAbandonedTimeout="30"
       logAbandoned="true"
        validationQuery="select 1" />

</GlobalNamingResources>

Fatto questo, per poter rendere visibile al contesto web della nostra webapplication il driver, senza essere costretti a registrarlo manualmente tramite il DriverManager, mettiamo un resource-link o copiamo direttamente l’xml della definizione resource sopra inserita, nel file context.xml della cartella conf di tomcat, od in un file context.xml nella cartella META-INF della webapplication.
Dovendo rilasciare l’applicazione su diversi application server, preferisco non portare specifici files di configurazione nell’applicazione(ove possibile) e quindi lascio il file context.xml nella cartella config del server tomcat.

Contenuto del context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
--><!-- The contents of this file will be loaded for each web application --><Context>

    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <Resource name="jdbc/testdb" auth="Container" type="javax.sql.DataSource"
        username="kiraya"
        password="kiraya"
        factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"

        driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
        url="jdbc:sqlserver://xx.xx.xx.xx:1433;DatabaseName=MYDB"
        maxActive="50"
        maxIdle="10"
        maxWait="15000"
        removeAbandoned="true"
        removeAbandonedTimeout="30"
        logAbandoned="true"
        validationQuery="select 1" />    -->

    <!-- Uncomment this to enable Comet connection tacking (provides events
         on session expiration as well as webapp lifecycle) -->
    <!--
    <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
    -->

</Context>

Fatto questo, possiamo utilizzare una lookup jndi nella maniera classica per ottenere una connessione db.

1
2
3
javax.naming.InitialContext context = new javax.naming.InitialContext();
DataSource ds = (DataSource)context.lookup("java:/comp/env/jdbc/testdb");
Connection conn = ds.getConnection();

Se tomcat è configurato come server Runtime dentro eclipse, e quindi lo start e stop viene fatto da li, allora il file context da modificare non è quello della cartella conf del server ma quella della versione gestita da Eclipse, generalmente contenuta nel workspace, nella cartella Server..

MongoDB , JavaDriver e Full Text Search

Con le nuove versioni di MongoDB, è stata portata alla luce, anche sul driver java ,la possibilità di avere indici testuali su cui effettuare ricerche.

Per definire l’indice ed eseguire una ricerca:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 MongoClient mongo = new MongoClient("localhost",27017);
 DB db = mongo.getDB("persons");
 DBCollection table = db.getCollection("personCollection");
 //creo un indice full text sulla "colonna" name dell'oggetto Person
 table.createIndex(new BasicDBObject("name","text"));
 BasicDBObject search= new BasicDBObject("$search","valori da ricercare separati da spazio");
 BasicDBObject textSearch = new BasicDBObject("$text",search);
 DBCursor cursor = tablefind(textSearch);
 personList = new ArrayList<Person>();
       
 while (cursor.hasNext()){
  DBObject obj = cursor.next();
  Person pers = (new Gson()).fromJson(obj.toString(), Person.class);
  personList.add(pers);
 }

Fare attenzione alla versione che si usa di MongoDB perché nelle versioni precedenti la full text search non era abilitata di default.

Interessante la possibilità di ottenere come risultato l’item con il più alto numero di match di parole chiave inserite:

1
2
3
4
  BasicDBObject search= new BasicDBObject("$search","valori da ricercare separati da spazio");
  BasicDBObject textSearch = new BasicDBObject("$text",search);
  BasicDBObject score= new BasicDBObject("score", new BasicDBObject("$meta", "textScore"));
  bestItem= coll.findOne(textSearch, score);

MongoDB e Java Driver,esempi vari

Iniziamo a giocare con MongoDB tramite il java driver.
Consiglio il download della versione 2.12.3 o successive (fate attenzione che i downloads della libreria non sono in ordine numerico, e quindi si rischia spesso di scaricarne una vecchia).
Altra libreria utile per le conversioni da pojo a stringa, la libreria Google gson, versione 2-2-4.

Una volta messo il jar nel classpath della nostra applicazione, e fatto partire il nostro server database mongodb, stabiliamo la connessione, al server e otteniamo il riferimento al database che vogliamo usare, in questo caso il db “person”. Ottenuto il DB, possiamo accedere alla collection dei nostri futuri oggetti da persistere (se la collection non esiste, viene creata in questa fase).

1
2
3
MongoClient mongo = new MongoClient("localhost",27017);
DB db = mongo.getDB("persons");
DBCollection table = db.getCollection("personCollection");

Realizziamo un pojo classico per la gestione dell’entità “Person” da persistere su MongoDB.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.io.Serializable;

public class Person implements Serializable{

    private static final long serialVersionUID = -8413862529676269210L;
    private String id = java.util.UUID.randomUUID().toString();
    private String name;
    private String lastname;
    private Integer age;
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
   
    public String getId() {
        return id;
    }
   
    public void setId(String id) {
        this.id = id;
    }
   
   
}

In questo esempio generiamo un UUID come id dell’oggetto, ma potremmo usare l’hashcode.

Per effettuare una insert sulla collection di cui sopra:

1
2
3
4
5
6
7
8
9
10
//istanza dell'oggetto Person da inserire
Person persona = new Person();
persona.setName("cesare");
//utilizziamo JSon per la conversione automatica da pojo a BasicDBObject

Gson gson = new Gson();
BasicDBObject personDBO =(BasicDBObject) JSON.parse(gson.toJson(persona));

//table è la DBCollection indicata nel primo esempio
table.insert(personDBO );

Col nuovo driver è possibile usare operazioni batch in automatico passando all’insert un array

1
2
3
4
5
6
7
8
List<DBObject> dbObjList = new ArrayList<DBObject>();
for(int i =0;i<100;i++){
 Person p = new Person();
 p.setName("test"+i);
 BasicDBObject pDB=(BasicDBObject) JSON.parse(gson.toJson(p));
 dbObjList.add(pDB);
}
table.insert(dbObjList);

Per la modifica di un oggetto in una collection (per definizione con MongoDB parliamo in realtà di documenti), è possibile effettuare direttamente il replace dell’oggetto con una nuova istanza.

1
2
3
4
5
6
7
 //creo un dbObject per eseguire la find di un elemento che abbia la chiave name uguale a 'test1':
 BasicDBObject personOriginal = new BasicDBObject().append("name", "test1");
 
 //e sostituirlo con questo nuovo oggetto
 BasicDBObject personNew = new BasicDBObject().append("name","nuovotest1").append("lastname","kiraya");

 table.update(personOriginal,personNew);

Per rimuovere un elemento dalla collection,è possibile indicare un criterio di ricerca oppure un DBObject specifico da eliminare:

1
2
3
 BasicDBObject personQuery = new BasicDBObject().append("name","nuovotest1");
 BasicDBObject personDB = table.findOne(personQuery);
 table.remove(personDB);

Per svuotare completamente una collection, è possibile eseguirne il drop:

1
 table.drop();

Oppure usare un BasicDBObject “byExample” che non contenga dati, il che sta a significare una rimozione senza nessun particolare criterio di filtro (e quindi tutti):

1
table.remove(new BasicDBObject());

E’ possibile filtrare i dati in diversi modi, utilizzando le query byExample, utilizzando il QueryBuilder oppure tramire Regular Expressions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//by example il contenuto deve matchare completamente
DBCursor cursor = table.find(new BasicDBObject("name","test1"));
while (cursor.hasNext()){
  DBObject obj = cursor.next();
  Person pers = (new Gson()).fromJson(obj.toString(), Person.class);
  System.out.println(pers.getName());
}

//tramite regexp utilizzando un pattern per simulare una like %nome%
BasicDBObject filter= new BasicDBObject();
filter.append("name", Pattern.compile("nuovo"));
filter.append("lastname",Pattern.compile("kira"));
cursor = table.find(filter);
while (cursor.hasNext()){
  DBObject obj = cursor.next();
  Person pers = (new Gson()).fromJson(obj.toString(), Person.class);
  System.out.println(pers.getName());
}

Per estrarre tutti gli elementi di una collection basta eseguire un find senza parametri:

1
DBCursor cursor = table.find();