====== 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}}