wtorek, 22 listopada 2011

Programowanie aspektowe – aspekty statyczne

W części pierwszej opisane zostały aspekty dynamiczne, czyli dodatki do istniejących klas i metod. Tym razem opiszę aspekty statyczne. Aspekty te pozwalają dodać nowe metody i pola do istniejących klas.
Aaa:
package kkk;

public class Aaa {

    public static void main(String[] args) {

 Obiekt samochodzik = new Obiekt((float) 99.99);
 System.out.println("cena - " + samochodzik.getCena());

 System.out.println("po podatku - " + samochodzik.dodajPodatek(99));
 System.out.println("po uldze - " + dodajUlge(99));

    }

    public static float dodajUlge(float cena) {
 return cena - cena * ulga / 100;
    }
}
AddMethod:
package kkk;

public aspect AddMethod {
    public static float podatek = 23;
    public static int Aaa.ulga = 15;

    public float Obiekt.dodajPodatek(float cena) {
 return cena + cena * podatek / 100;
    }
}
Obiekt:
package kkk;

public class Obiekt {
    private float cena;

    public Obiekt(float cena) {
 this.setCena(cena);
    }

    public float getCena() {
 return cena;
    }

    public void setCena(float cena) {
 this.cena = cena;
    }
}
Wynik:
cena - 99.99
po podatku - 121.770004
po uldze - 84.15

Jak widać w przykładzie aspekt dodaje jedną metodę do klasy Obiekt i jedno pole do klasy Aaa.
Na tych metodach i polach można operować tak samo jak na tych napisanych wprost.

czwartek, 10 listopada 2011

Czytywanie z i zapis do pliku

Dwie podstawowe operacje wykorzystywane przy pracy z plikami tekstowymi.

Wczytywanie pojedynczej linii z pliku:
public static void odczyt() {
 Scanner odczyt = null;
 try {
     odczyt = new Scanner(new File("C:/pliktekstowy.txt"));
 } catch (FileNotFoundException e) {
     e.printStackTrace();
 }
 String zdanie = odczyt.nextLine();
 System.out.println(zdanie);
    }
Zapis do pliku:
public static void zapis() {
 PrintWriter zapis = null;
 try {
     zapis = new PrintWriter("C:/pliktekstowy2.txt");
 } catch (FileNotFoundException e) {
     e.printStackTrace();
 }
 zapis.println("Hello World");
 zapis.close();
    }

środa, 2 listopada 2011

Programowanie aspektowe - AspectJ

Paradygmat programowania, który wspomaga separację programu na części jak najbardziej ze sobą niezwiązane. Pozwala zredukować ilość pisanego kodu, jednocześnie dzieląc program na logiczne moduły. Zmienia układ modułów widoczny dla programisty, po skompilowaniu do bytecodu jest całkowicie normalnym programem.
Styl programowania aspektowego stosowany jest do np. wydzielenia z kodu programu metod logowania. Zamiast w każdej klasie, czy metodzie pisać linijkę kodu zawierającą zapis do dziennika (log), można to wydzielić do aspektu, czyli innej klasy, która będzie wyszukiwała odpowiednią metodę i sama doda tą linijkę.

Główne zastosowania:
  • Zarządzanie transakcjami
  • Kontrola dostępu
  • Zarządzanie współbieżnym wykonaniem
  • Audyt/Monitorowanie
  • Wstrzykiwanie zależności
  • Uproszczenie wzorców projektowych
  • Narzędzia do generowania kodu infrastruktury

Instalacja:
W Eclipsie -> Help -> Install New Software… -> wpisujemy strone: http://download.eclipse.org/tools/ajdt/37/update -> wybieramy AspectJ Development Tools -> instalujemy

HelloWorld:
Aby utworzyć nowy projekt w AspectJ wybieramy:
File -> New -> Other… ->AspectJ -> Aspect Project
Możemy tworzyć zwykłe projekty Javy, do tego mogąc dodać aspekt.
public class Main {

    public static void main(String[] args) {
 HelloWorld.say("wiadomosc");
 HelloWorld.sayToPerson("wiad", "name");
    }
}
public class HelloWorld {
    public static void say(String message) {
 System.out.println(message);
    }

    public static void sayToPerson(String message, String name) {
 System.out.println(name + "," + message);
    }
}
Klasa AspectJ: PPM na projekcie -> New -> Other… -> AspectJ -> Aspect
public aspect MannersAspect {
    pointcut callSayMessage() : call( public static void HelloWorld.say*( . . ) ) ;

    before() : callSayMessage ( ) {
 System.out.println("Good day ! ");
    }

    after() : callSayMessage() {
 System.out.println("Thank you ! ");
    }
}
Uruchomienie: PPM na klasę Main -> Run as -> AspectJ/Java Application
Otrzymany wynik:
Good day !
wiadomosc
Thank you !
Good day !
name,wiad
Thank you !

Powyższy przykład pokazuje jak bez ingerencji w metody można dodać przed ich wykonaniem i po ich zakończeniu komunikat.
Teraz dodam kolejny aspekt obliczający czas wykonania wszystkich metod publicznych:
public aspect TimeAspect {
    pointcut publicTime() : execution(public * *.*(..)) && !execution(* Main.*(..));

    Object around() : publicTime() {
 long time = System.nanoTime();
 Object ret = proceed();
 System.out.println(System.nanoTime() - time);
 return ret;
    }
}
Wynik programu:
Good day !
wiadomosc
65698
Thank you !
Good day !
name,wiad
98034
Thank you !

Jak wygląda aspekt?
Aspekt jest traktowany jak zwykła klasa, zamiast class użyty jest aspect.
Ciało aspektu składa się z:
  • pointcut,
  • advice,

pointcut (definicja przecięcia)
Określa kontekst, dla którego ma działać aspekt, tzn. specyfikuje dla jakich metod (np. publicznych), o jakich nazwach (albo np. początkach nazw (HelloWorld.say*)-gwiazdka oznacza, że może być tu dowolny tekst), czy dla metod z jakimi parametrami aspekt ma być stosowany.

Specyfikator pointcut nazwa() : typ sygnatura
  • Specyfikator – tak jak w zwykłych metodach public, private…
  • pointcut – słowo kluczowe,
  • nazwa() – nazwa naszego przecięcia – może zawierać parametry, które są przekazywane w przechwytywanych metodach,
  • typ: call albo execution. Zazwyczaj dają taki sam efekt,
  1. call – aspekt wplatany jest w każde miejsce wywołania metody
  2. execution – aspekt wplatany jest w ciało przechwyconej metody, bardziej preferowana
  • Sygnatura – określa jakie metody aspekt ma przechwytywać, określa kolejno :
  1. adnotacje (opcjonalne)
  2. modyfikatory (opcjonalne)
  3. zwracaną wartość (wymagane)
  4. pakiet (opcjonalnie)
  5. klasę (wymagane)
  6. nazwę metody (wymagane)
  7. parametry (wymagane)

Przykład:
Zastosowane wszystkie parametry:
pointcut p1() : execution (@Special public void p2.App.m1(String));
Zastosowane tylko wymagane parametry:
pointcut p1() : execution (void App.m1(String));

Wieloznaczniki:
Zamiast wpisywania wszystkich parametrów można użyć wieloznaczników typu: * .. +
  • * oznacza wiele znaków (ale bez kropki),
  • .. oznacza wiele znaków (również kropki),
  • + rozszerza określenie typu o dowolny podtyp,

execution (void ppp.kkk.*(*)); - wszystkie metody w klasie “kkk” paczki „ppp”
execution (* ppp.*.*()); - wszystkie metody bez parametrów w paczce „ppp”,
execution (* ppp..*.*(..)); - oznacza paczkę „ppp” i wszystkie podrzędne pakiety metoda bez lub z dowolną ilością parametrów,

advice (rada):
miejsce(parametry) : nazwaPointcuta(parametry){
ciało metody
}
miejsce - określa w którym miejscu ma być wykonany kod aspektu:
  • before(): rada zostanie wykonana przed przechwyconym punktem złączenia,
  • around(): rada zostanie wykonana zamiast punktu złączania, chyba że metoda proceed() nakazuje inaczej,
  • after(): rada zostanie wykonana po przechwyconym punkcie złączenia, niezależnie od wyniku wykonania tego punktu;,
  • after() returning: rada zostanie wykonana po przechwyconym punkcie złączenia wyłącznie wtedy, gdy punkt ten wykonał się nie zgłaszając wyjątku;,
  • after() throwing: rada zostanie wykonana po przechwyconym punkcie złączenia wyłącznie wtedy, gdy punkt ten wykonał się zgłaszając wyjątek,

Przykład aspektu z parametrami:
public aspect ValidAspect {
    pointcut valid(int a) :
 call( public static int HelloWorld.sprawdz(int) ) && args(a) ;

    before(int a) : valid (a) {
 System.out.println("Good day ! " + a);
 if (a == 9) {
     System.out.println("----- znaleziono 9 -----");
 }
    }

    after(int a) : valid(a) {
 System.out.println("Thank you ! ");
    }
}
Część druga - aspekty statyczne.