====== Program w języku Java ======
Celem zajęć będzie rozwinięcie prostego apletu - czyli programu osadzonego na stronie HTML...
Program będzie bardzo podobny do poprzedniego napisanego w języku C++, również pojawi się w nim hierarchia //Shape// oraz //ShapeFactory//.
===== Tworzymy aplet =====
==== Projekt ====
Wybierz //File -> New -> Java Project//. Wprowadź ''ShapesApplet'' jako nazwę projektu.
{{:swo:swo-shapes-applet.png?400}}
Utworzony zostanie pusty projekt.
==== Klasa ShapesApplet ====
Wybierz //File -> New -> Java Class//
*Wprowadź nazwę klasy ''ShapesApplet''
*Wprowadź nazwę pakietu ''pl.edu.agh.kis.snwo''
{{:swo:swo-2-shapes-applet-class.png?400}}
Wprowadź metodę ''paint()'' i nie zapomnij o **''extends Applet''**. Metoda ''paint()'' zostanie wywołana za każdym razem, kiedy trzeba będzie przerysować okno apletu.
public class ShapesApplet extends Applet{
/**
*
*/
public void paint(Graphics g){
g.drawLine(10, 10, 100, 100);
g.drawLine(10, 100, 100, 10);
}
}
Wybierz //Run// i jako konfigurację wskaż //Run as applet//. Uruchomione zostanie narzędzie appletviewer, a w nim narysowane dwie skrzyżowane linie.
{{:swo:swo-2-appletviewer.png?200}}
*Teoretycznie, można aplet uruchomić w oknie przeglądarki. Ale ostatnio polityka bezpieczeństwa wdrożona w przeglądarkach zaostrzyła się i z lokalnego dysku nie da się załadować apletu (przynajmniej bez zmiany domyślnych ustawień).
*Po umieszczeniu apletu na serwerze HTTP, już jest to możliwe. Jeśli ktoś ma konto w UCI, powinno się udać [[http://www.uci.agh.edu.pl/porady-uci/#strona]]
Aby wyświetlić aplet w oknie przeglądarki, jego kod musi być osadzony na stronie HTML. Przykładowa strona wygląda następująco:
Shapes Applet
Po przesłaniu plików na serwer...
*test.html
*pl
*edu
*agh
*kis
*snwo
*ShapeApplet.class
...i wybraniu odpowiedniego adresu w oknie przeglądarki aplet uruchomi się.
:!: Proszę zwrócić uwagę na rozmieszczenie plików. Każdy człon nazwy pakietu odpowiada katalogowi.
{{:swo:swo-2-browser.png?500}}
===== Dodajemy do apletu rysowanie wektorów =====
==== Dodajemy klasę Shape ====
Wybierz //File -> New -> Java Class// i jako nazwę klasy wprowadź ''Shape''.
Klasa powinna trafić do pakietu ''pl.edu.agh.kis.snwo''
package pl.edu.agh.kis.snwo;
import java.awt.Color;
import java.awt.Graphics;
public class Shape {
Color c=Color.black;
void draw(Graphics g){}
}
==== Dodajemy klasę Line ====
Wybierz //File -> New -> Java Class// i jako nazwę klasy wprowadź ''Line''. Wprowadź w polu //superclass// (klasa bazowa) ''Shape''.
{{:swo:swo-2-line.png?400}}
Wprowadź kod:
package pl.edu.agh.kis.snwo;
import java.awt.Graphics;
public class Line extends Shape {
int x1;
int y1;
int x2;
int y2;
void draw(Graphics g){
g.setColor(c);
g.drawLine(x1, y1, x2, y2);
}
}
==== Dodajemy klasę Circle i Rectangle ====
*Postępujemy analogicznie, jak poprzednio. Wybieramy takie same atrybuty jak dla programu w C++.
*Podobnie implementujemy metody ''draw'' wywołując ''g.drawOval()'' oraz ''g.drawRect()''. Proszę przeczytać ich opisy, aby poprawnie je wywołać.
==== Pierwsza refaktoryzacja ====
Nie podoba nam się występujące w trzech miejscach ''g.setColor( c )''. Bardziej podobałoby się ''g.setColor(color)''.
**Zmieniamy nazwę odziedziczonego atrybutu**
*Idziemy do ''Shape.java''.
*Zaznaczamy ''c'' i wybieramy //Refactor->Rename...//.
*Wprowadzamy nową nazwę ''color''
*W **każdym miejscu** zostanie zmieniona nazwa atrybutu.
==== Dodajemy ShapeFactory ====
Odtworzymy projekt klasy zaimplementowanej w języku C++
public class ShapeFactory {
private ShapeFactory(){}
private static ShapeFactory _theFactory = new ShapeFactory();
static ShapeFactory get(){return _theFactory;}
Shape createLine(int x1,int y1,int x2,int y2){
Line s= new Line();
s.x1=x1;
s.x2=x2;
s.y1=y1;
s.y2=y2;
return s;
}
Shape createCircle(int x,int y,int r){
//...
}
Shape createRectangle(int x1,int y1,int x2,int y2){
//...
}
}
Jak poprzednio:
*Konstruktor jest prywatny
*Jest jedna statyczna instancja klasy
*Metoda ''get()'' pozwala zrealizować do niej dostęp
*Ponieważ operatorem zasięgu w Javie jest kropka, będziemy wołać ''ShapeFactory.get().createRandomShape()''
=== Piszemy createRandomShape ===
W metodzie ''createRandomShape()'' była wołana funkcja ''rand()''. Napiszemy ją, aby nie przerabiać kodu
Random generator = new Random(System.currentTimeMillis());
private int rand(){
return generator.nextInt(1234567);
}
Shape createRandomShape(){
int choice = rand()%3;
switch(choice){
case 0:
return createLine(rand()%300,rand()%300,rand()%800,rand()%900);
case 1:
return createCircle(rand()%900,rand()%900,rand()%300);
case 2:
return createRectangle(rand()%300,rand()%300,rand()%800,rand()%900);
}
return null;
}
==== Modyfikujemy kod apletu ====
*Dodajemy tablicę referencji typu ''Shape'' o rozmiarze ''SIZE''
static final int SIZE = 100;
Shape[]table = new Shape[SIZE];
*W //publicznym// konstruktorze inicjujemy ją losowo wygenerowanymi wektorami
public ShapesApplet(){
for(int i=0;i
*Zmianiamy metodę ''paint()''. Mam nadzieję, że rozpoznajecie Państwo konstrukcję //foreach//.
public void paint(Graphics g){
for(Shape s:table){
s.draw(g);
}
}
== Uruchamiamy ==
{{:swo:swo-2-applet-bw.png?400}}
===== Dodajemy kolory =====
Oczywiście, mogliśmy od razu wprowadzić docelowy kod, ale celem jest zapoznanie się z możliwościami refaktoryzacji. Więc kolory dodajemy później...
==== Refaktoryzacja: dodawanie parametru do istniejącej funkcji====
Poza losową generacją rozmiarów wektorów, chcemy, aby miały one losowo wybrane kolory. Funkcje ''createLine()'', ''createRectangle()'' i ''createCircle()'' raczej nie powinny losować kolorów. Przekażemy je do nich jako parametr ustawiany w ''createRandomShape''
*Zaznacz metodę ''createLine()'' w kodzie ''ShapeFactory''.
*Wybierz //Refactor->Change Method Signature...//
*Dodaj w nowy parametr metody ''Color color''
{{:swo:swo-2-add-param.png?400}}
*Przejrzyj zmiany w kodzie ''createRandomShape()''
*Spróbuj zmienić kolejność parametrów (możesz to zrobić w dowolnym momencie). Proponuję, aby ''Color color'' pojawił się na początku.
==== Zmieniamy kod funkcji ====
Tak, jak poniżej -- musimy coś z parametrem kolor zrobić.
Shape createLine(Color color,int x1,int y1,int x2, int y2){
Line s= new Line();
s.color=color;
s.x1=x1;
s.x2=x2;
s.y1=y1;
s.y2=y2;
return s;
}
Wprowadzamy ''s.color=color;'' dla ''Rectangle'' i ''Circle''.
==== Dodajemy losową generację kolorów ====
Shape createRandomShape(){
Color color = new Color(rand()%256,rand()%256,rand()%256);
int choice = rand()%3;
switch(choice){
case 0:
return createLine(color,rand()%300,rand()%300,rand()%800, rand()%900);
case 1:
return createCircle(color,rand()%900,rand()%900, rand()%300);
case 2:
return createRectangle(color,rand()%300,rand()%300,rand()%800, rand()%900);
}
return null;
}
i po uruchomieniu otrzymujemy...
{{:swo:swo-2-applet-color.png?400}}
===== Dystrybucja apletu =====
==== Tworzymy archiwum jar ====
Programy napisane w Javie z reguły są dystrybuowane w postaci archiwów //jar//. Nazwa jest luźno związana ze słoikiem ;-) Raczej jest to skrót od **J**ava **AR**chive. W gruncie rzeczy jest to zwykły zip, w którym umieszczany jest skompilowany kod klas oraz (opcjonalnie) dodatkowe pliki zawierające klucze użyte do podpisu i sumy kontrolne plików //class//.
*Dodaj folder do projektu i nazwij go ''build''. Wybierz //File->New->Folder//
*Wybierz opcję //File->Export->Java->JAR File//
*W oknie dialogowym wybierz elementy do eksportu i docelowy folder
{{:swo:swo-2-export-jar.png?400}}
*Plik JAR pojawi się w katalogu //build//
==== Dodajemy stronę HTML ====
W odróżnieniu od poprzedniego przykładu pojawił się atrybut ''archive="ShapesApplet.jar"''
Shapes Applet
Następnie otwieramy ją w przeglądarce. 8-o Niestety - nie udaje się uruchomić apletu? Nie pozwalają na to domyślne ustawienia przeglądarki.
==== Podpisujemy aplet ====
Zazwyczaj przeglądarka pozwala na uruchomienie podpisanego apletu, nawet przy użyciu testowego certyfikatu. Ten docelowy powinna wygenerować zaufana instytucja (i pobrać za to opłatę).
Podpisywanie pliku jar jest procesem dwuetapowym:
*Wpierw generujemy testowy certyfikat użyty do podpisu za pomocą narzędzia //keytool//. (Musimy podać hasło, oraz możemy imie, nazwisko, nazwę instytucji, itp.)
*Następnie osadzamy go w pliku JAR za pomocą narzędzia //jarsigner//
"c:/Program Files/Java/jdk1.6.0_31/bin/keytool.exe" -genkey -alias mojeid
"c:/Program Files/Java/jdk1.6.0_31/bin/jarsigner.exe" ShapesApplet.jar mojeid
==== Otwieramy lokalny plik w przeglądarce ====
Jeśli udało się wykonać poprzedni krok - możemy załadować plik do przeglądarki z lokalnego systemu plików. Możemy go także umieścić na serwerze HTTP (jesli mamy do niego dostęp).
{{:swo:swo-2-applet-color-browser.png?500}}