martedì 27 settembre 2011

Tomcat e VisualVM

VisualVM è un'applicazione messa a disposizione nel Java Development Kit a partire dalla versione 6, update 7, e permette di monitorare tutte le applicazioni Java in esecuzione sul sistema.
L'applicazione non va installata e l'eseguibile si trova nella cartella bin della cartella di installazione JDK.
All'avvio, VisualVM mostra in automatico tutte le applicazioni che sono in esecuzione sul sistema, ma tramite alcune configurazioni, può anche monitorare JVM remote che abbiano porte aperte e accessibili tramite JMX.

Per farlo è sufficiente aggiungere alla configurazione di Tomcat dell'applicazione remota, le seguenti righe

-Dcom.sun.management.jmxremote.port=8086
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false


Dopo di che sarà necessario riavviare Tomcat e aggiungere una connessione JMX in VisualVM che punti alla porta 8086.



Per approfondire:
Monitoring Tomcat with Java VisualVM
VisualVM, troubleshooting per Java

venerdì 29 luglio 2011

ImageHyperlink



Magari può essere utile sapere che esiste un oggetto Hyperlink fatto apposta per le immagini. Esempio:

ImageHyperlink logsExcelExport = new ImageHyperlink(parent, SWT.CENTER);

Image image = ImageDescriptor.createFromURL(Platform.getBundle(AssessmentBaseErrorCodes.ASSESSMENT_CLIENT_BASE_PLUGIN_ID).getEntry("icons/action-savexls.png")).createImage();
logsExcelExport.setImage(image);
logsExcelExport.setLayoutData(GridDataFactory.swtDefaults().align(SWT.END, SWT.END).hint(17, SWT.FILL).create());
logsExcelExport.setToolTipText("Esporta in Excel");


Come dice il nome, genera un'immagine cliccabile.

lunedì 18 luglio 2011

Testing methods secured with Spring Security

Spring Security allows to secure access to methods, allowing execution only for user with defined roles.

For example, using annotation to configure the roles required:

public interface MyService
{

 @PreAuthorize("hasRole('USER') OR hasRole('ADMIN')")
 void hello();

 @PreAuthorize("hasRole('ADMIN')")
 void bye();

}

In order to call the bye() method the user must have the ADMIN role, for hello() method also the the USER role is enough.

If a secured method is called by a user without the needed roles is raised an exception of type org.springframework.security.access.AccessDeniedException.

Method security is active even during tests, so we have developed an annotation and a listener that can be used to setup easily user roles when testing (we use TestNG, probably something like this can be done also with Junit).

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Authenticate {

 String username() default "";

 String[] roles() default {};
}

public class AuthenticationListener implements IInvokedMethodListener
{

 public static final String DEFAULT_USERNAME = "default";

 private static final String FAKE_PASSWORD = "fakePassword";

 /**
  * {@inheritDoc}
  */
 @Override
 public void beforeInvocation(IInvokedMethod method, ITestResult testResult)
 {
  if (method.isTestMethod())
  {
   ITestNGMethod testMethod = method.getTestMethod();
   Method javaMethod = testMethod.getMethod();
   Authenticate userAnnotation = javaMethod.getAnnotation(Authenticate.class);
   if (userAnnotation != null)
   {
    String username = userAnnotation.username();
    if (username == null || username.isEmpty())
    {
     username = DEFAULT_USERNAME;
    }
    String[] roles = userAnnotation.roles(); // role may be null/empty
    authenticateUser(username, roles);
   }
  }
 }

 private void authenticateUser(String username, String... roles)
 {
  Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
  if (roles != null)
  {
   for (String role : roles)
   {
    grantedAuthorities.add(new GrantedAuthorityImpl(role));
   }
  }
  UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, FAKE_PASSWORD,
   grantedAuthorities);
  SecurityContextHolder.getContext().setAuthentication(token);
 }

 /**
  * {@inheritDoc}
  */
 @Override
 public void afterInvocation(IInvokedMethod method, ITestResult testResult)
 {
  if (method.isTestMethod())
  {
   SecurityContextHolder.clearContext();
  }
 }

}

The Authenticate annotation allows to set the username and a list of roles that must be used when executing a test method, the AuthenticationListener take care to configure the authentication token before test execution and to reset the security context after execution.

This is an example of a test method that uses the Authenticate annotation:

@ContextConfiguration("classpath:META-INF/spring/applicationContext*.xml")
@Listeners(AuthenticationListener.class)
public class MyServiceTest extends AbstractTestNGSpringContextTests
{

 @Autowired
 private MyService myService;

 @Test
 @Authenticate(username = "pippo", roles = {"ADMIN" })
 public void testCallHelloAsAdmin()
 {
  myService.hello();
 }

 @Test
 @Authenticate(username = "pippo", roles = {"USER" })
 public void testCallHelloAsUser()
 {
  myService.hello();
 }

 @Test
 @Authenticate(username = "pippo", roles = {"ADMIN" })
 public void testCallByeAsAdmin()
 {
  myService.bye();
 }

 @Test(expectedExceptions = AccessDeniedException.class)
 @Authenticate(username = "pippo", roles = {"USER" })
 public void testCallByeAsUser()
 {
  myService.bye();
 }
}


See also:
The demo project on GitHub
Spring Security
TestNG Listeners
Annotations

martedì 12 luglio 2011

Liquibase migration for Spring Security tables

Spring security default implementation requires to access to a database in order to do its job.

Here is the liquibase migration file for creating these tables.

The changesets 1, 2 and 2a create tables for authentication and authorization.
Changesets 3, 3a, 4, 5, 6 and 6a create tables for domain object security (ACL).
Tha last changeset, 7, insert some data in tables (2 users wioht their roles).



This migration is customized for MySql database, enforces the InnoDB engine when creates tables, but should work also on other databases.

See also:
Spring Security
Security Database Schema
Liquibase

mercoledì 22 giugno 2011

Recupero della versione del pom all'interno di una classe java

Java permette di recuperare la versione di un jar tramite codice. La versione deve essere dichiarata all'interno del manifest nell'attributo Implementation-Version.
Per un progetto maven è sufficiente customizzare la generazione del manifest configurando il maven-jar-plugin nel pom:
[...]

 
  
   org.apache.maven.plugins
   maven-jar-plugin
   true
   
    
     
      
      it.sinossi.poc.Main
      
      true
     
    
   
  
 

[...]

Nel codice java possiamo recuperare la versione con il seguente codice:
String version = getClass().getPackage().getImplementationVersion(); 

Questa soluzione funziona solo eseguendo il jar, se per esempio viene eseguito
il codice da eclipse la variabile version sarà null.


Per maggiorni informazioni vedere anche:

Package.getImplementationVendor()
Maven - Manifest customization

lunedì 28 febbraio 2011

Netstat: ricavare informazioni sulla rete

Dal man di netstat:
Netstat prints information about the Linux networking subsystem.
Si tratta di un comodo comando che permette di ottenere informazioni sul sistema di rete.

Lanciando il comando senza parametri vengono visualizzati i socket unix aperti e le connessioni internet attive (connessione ai server di posta, dns, etc)

Se invece si volessero visualizzare i socket aperti verso l'esterno (in ascolto) è necessario passare qualche altro parametro. Il comando

netstat -l --inet


mostra i socket aperti, ma è lento poiché esegue delle query dns per risalire al nome del dominio a partire dall'indirizzo IP. Usando il parametro -n, netstat mostrerà direttamente gli indirizzi IP e i numeri delle porte.

Se oltre a sapere quali socket sono attivi, si vuole sapere quali processi li stanno utilizzando, il comando

netstat -p -n -l --inet

permette di scoprirlo.

I parametri utilizzati finora sono:
-p stampa il nome del programma e il pid del processo principale
-n stampa indirizzi numerici al posto di nomi di host, tipi di porte e nomi utente
-l stampa solo i socket in ascolto (normalmente questa opzione non è attiva)
--inet stampa solo i socket di tipo inet (i classici socket tcp/udp); esclude la visualizzazione dei socket unix

Altri parametri utili sono:
-e visualizza informazioni estese (utente esecutore del processo, etc)
-c netstat rimane in esecuzione e ogni secondo mostra l'informazione richiesta
--tcp visualizza solo i socket TCP
--udp visualizza solo i socket UDP
-4 visualizza solo i socket via IPv4
-6 visualizza solo i socket via IPv6

mercoledì 9 febbraio 2011

ScrollableComposite: quello che la documentazione non dice

Come dice la documentazione, lo ScrolledComposite consente di visualizzare il suo contenuto con lo scorrimento delle barre verticali e orizzontali.

La documentazione è abbastanza dettagliata, fornisce anche un esempio.


public static void main(String[] args)
{
Display display = new Display();
Color red = display.getSystemColor(SWT.COLOR_RED);
Color blue = display.getSystemColor(SWT.COLOR_BLUE);
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());

// set the size of the scrolled content - method 1
final ScrolledComposite sc1 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
final Composite c1 = new Composite(sc1, SWT.NONE);
sc1.setContent(c1);
c1.setBackground(red);
GridLayout layout = new GridLayout();
layout.numColumns = 4;
c1.setLayout(layout);
Button b1 = new Button(c1, SWT.PUSH);
b1.setText("first button");
c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));

// set the minimum width and height of the scrolled content - method 2
final ScrolledComposite sc2 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
sc2.setExpandHorizontal(true);
sc2.setExpandVertical(true);
final Composite c2 = new Composite(sc2, SWT.NONE);
sc2.setContent(c2);
c2.setBackground(blue);
layout = new GridLayout();
layout.numColumns = 4;
c2.setLayout(layout);
Button b2 = new Button(c2, SWT.PUSH);
b2.setText("first button");
sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));

Button add = new Button(shell, SWT.PUSH);
add.setText("add children");
final int[] index = new int[]{0 };
add.addListener(SWT.Selection, new Listener()
{

public void handleEvent(Event e)
{
index[0]++;
Button button = new Button(c1, SWT.PUSH);
button.setText("button " + index[0]);
// reset size of content so children can be seen - method 1
c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));
c1.layout();

button = new Button(c2, SWT.PUSH);
button.setText("button " + index[0]);
// reset the minimum width and height so children can be seen - method 2
sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
c2.layout();
}
});

shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}


L'esempio funziona, aggiungendo del contenuto (in questo caso dei bottoni) le scrollbar appaiono non appena il contenuto diventa più grande dell'area visibile.
Nella pratica però, una situazione così semplice (composite direttamente nella shell) non avviene praticamente mai, è molto più probabile che ci sia un meccanismo di scatole cinesi.. composite dentro composite dentro composite.
Se proviamo a mettere un Composite parent che contiene il nostro ScrollableComposite, già rischiamo che il meccanismo non funzioni più. Perchè?

La documentazione non dice che il parent di uno ScrollableComposite deve sempre avere un layout di tipo FillLayout. Questo è fondamentale per farlo funzionare.

Sotto un esempio più complesso del precedente:


public static void main(String[] args)
{
Display display = new Display();
Color blue = display.getSystemColor(SWT.COLOR_BLUE);
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());

FormToolkit toolkit = new FormToolkit(Display.getCurrent());

Composite container = toolkit.createComposite(shell, SWT.NONE);

// container.setLayout(new GridLayout()); NON FUNZIONA!!!!
container.setLayout(new FillLayout());

container.setLayoutData(new GridData(GridData.FILL_BOTH));

Section section = toolkit.createSection(container, ExpandableComposite.TWISTIE
| ExpandableComposite.COMPACT
| ExpandableComposite.TITLE_BAR);

section.setText("Section");
section.setLayout(new GridLayout());
section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
section.setVisible(false);

// set the minimum width and height of the scrolled content - method 2
final ScrolledComposite sc2 = new ScrolledComposite(section, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
sc2.setExpandHorizontal(true);
sc2.setExpandVertical(true);
final Composite c2 = new Composite(sc2, SWT.NONE);
sc2.setContent(c2);
c2.setBackground(blue);
GridLayout layout2 = new GridLayout();
layout2.numColumns = 4;
c2.setLayout(layout2);

for (int i = 0; i < 100; i++)
{
toolkit.createButton(c2, "button" + i, SWT.PUSH);
}

sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
section.setClient(sc2);
section.setVisible(true);
section.setExpanded(false);

shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}


Il layout di tipo Fill non consente di dimensionare a proprio piacimento lo spazio per posizionare per esempio due composite affiancati o uno sopra l'altro con altezze differenti (come invece consente il GridLayout). Ma ci sono altri meccanismi utili per fare questo come per esempio il SashForm.

venerdì 4 febbraio 2011

Eclipse RCP: aggiungere voci di menu dinamiche

Eclipse mette a disposizione un semplice meccanismo che permette di aggiungere in maniera dinamica delle voci ad un menu contestuale.

Per creare un menu è necessario dichiarare nel plugin.xml un estension point org.eclipse.ui.menus.
Supponiamo di voler aggiungere un nuovo menu alla toolbar dell'applicazione.
Aggiungiamo all'extension poin org.eclipse.ui.menus un menuContribution con

locationURI="menu:org.eclipse.ui.main.menu?after=additions"

Lo schema menu indica che il nuovo menu deve apparire sulla toolbar, mentre after=additions indica che deve apparire dopo i menu standard.

Al menuContribution aggiungiamo ora un menu, indicando id e label.


point="org.eclipse.ui.menus">
locationURI="menu:org.eclipse.ui.main.menu?after=additions">
id="it.sinossi.menu.toolbarMenu"
label="Menu Dinamico">





Aggiungiamo ora al menu un nodo di tipo dynamic e specifichiamo gli attributi id e class


point="org.eclipse.ui.menus">
locationURI="menu:org.eclipse.ui.main.menu?after=additions">
id="it.sinossi.menu.toolbarMenu"
label="Menu Dinamico">
id="it.sinossi.menu.sinossiCompoundContributionItem"
class="it.sinossi.menu.SinossiCompoundContributionItem">






La classe it.sinossi.menu.sinossiCompoundContributionItem deve estendere la classe astratta org.eclipse.ui.actions.CompoundContributionItem e implementare il metodo getContributionItems


import org.eclipse.jface.action.IContributionItem;
import org.eclipse.swt.SWT;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.CompoundContributionItem;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;


public class SinossiCompoundContributionItem extends CompoundContributionItem
{
private static int counter = 0;

@Override
protected IContributionItem[] getContributionItems()
{
final CommandContributionItemParameter contributionParameter =
new CommandContributionItemParameter(
PlatformUI.getWorkbench().getActiveWorkbenchWindow(),
"it.sinossi.menu.sinossiCompoundContributionItem",
"it.sinossi.command.dynamicCommand",
SWT.NONE);
contributionParameter.label = "Dynamic Menu Item " + counter++;
items[i] = new CommandContributionItem(contributionParameter);
}
return new IContributionItem[] { new CommandContributionItem(contributionParameter) };
}
}


Il metodo restituisce un array di IContributionItem. Ogni elemento dell'array è un oggetto di classe org.eclipse.ui.menus.CommandContributionItem, e rappresenta una voce da aggiungere al menu. Ogni CommandContributionItem è costruito a partire da un org.eclipse.ui.menus.CommandContributionItemParameter, che contiene le caratteristiche della voce stessa.
Nel suo costruttore infatti devono essere specificati l'id dell'elemento dynamic a cui associare il CommandContributionItem e l'id del command che dovra essere eseguito quando la voce viene selezionata.
Si noti che il metodo getContributionItems viene eseguito ogni volta che viene aperto il menu, perciò la variabile counter verrà incrementata ogni volta e questo fa si che la label della voce di menu sia aggiornata dinamicamente.

Nel plugin.xml aggiungiamo l'estension point org.eclipse.ui.commands per definire il command e l'handler di default che saranno attivati alla selezione della voce


point="org.eclipse.ui.commands">
id="it.sinossi.command.dynamicCommand"
defaultHandler="it.sinossi.command.DynamicCommand"
name="Dynamic Command">


mercoledì 5 gennaio 2011

Concaterare liste con Spring

E' possibile concatenare liste di oggetti in Spring.
Con Spring 2.5 esistono due possibilità:

1) utilizzando la gerarchia di bean





Foo






Bar






Ernie
Bert





In questo modo listTree conterrà [Foo, Bar, Ernie, Bert].
Se non si vuole introdurre una gerarchia di bean, bisogna seguire un'altra strada.

2) creando una classe apposita che esegue la concatenazione


package com.company.utils.spring;
import java.util.*;
import org.springframework.beans.factory.config.ListFactoryBean;

public class ListMergerFactory extends ListFactoryBean
{
private final List listOfLists;

public ListMergerFactory(List listOfLists) throws Exception
{
this.listOfLists = listOfLists;
setSourceList(new ArrayList());
}

protected Object createInstance()
{
List listOrigin = (List) super.createInstance();
for (Iterator iter = listOfLists.iterator(); iter.hasNext();)
{
List element = (List) iter.next();
listOrigin.addAll(element);
}
return listOrigin;
}
}


E utilizzandola per creare la lista finale:






Foo






Bar















Ernie
Bert





Anche in questo modo listTree conterrà [Foo, Bar, Ernie, Bert].