Obecnie co raz rzadziej spotykane są w sieci aplety Java. Od powstania tej technologi upłynęło sporo czasu oraz pojawiło się dużo nowych technologii webowych, dzięki którym można osiągnąć podobne możliwości. Czasem jednak przydaje się wykorzystanie tych konstrukcji. Z niewielkim wysiłkiem można zintegrować je również z aplikacją GWT. Jakiś czas temu potrzebowałem funkcjonalności przechwytywania obrazów z urządzeń TWAIN(skanery, aparaty fotograficzne) bezpośrednio z aplikacji GWT. I tutaj z pomocą przyszła zapomniana technologia Java Applet. Ale może o integracji GWT z urządzeniami TWAIN innym razem. Teraz chciałem pokazać prosty przykład komunikacji GWT i Java Applet.

Na początek tworzymy przykładowy aplet, który będzie wymieniał się komunikatami z aplikacją GWT. Aplikacja zawiera pole do wpisywania wiadomości, podpięty  pod to pole przycisk wysyłający wpisany komunikat oraz pole w którym wyświetlane są komunikaty, które przyszły od aplikacji GWT.

Ważną sprawą przy tworzeniu apletu jest podpisanie go cyfrowym certyfikatem. Wirtualna maszyna Javy uruchamia aplety na innych warunkach niż zwykłe aplikacje. Standardowe aplikacje są traktowe jako zaufane. Projektanci specyfikacji JVM założyli, że użytkownicy uruchamiający aplikację z własnej inicjatywy biorą odpowiedzialność za jej zachowanie. Z kolei aplety są uruchamiane automatycznie przez przeglądarkę, zaraz po ściągnięciu i otworzeniu strony. W związku z tym aplety są domyślnie niezaufane.

Rozwiązaniem tego problemu jest stworzenie certyfikatu, którym zostanie podpisany nasz aplet. W momencie gdy przeglądarka ściągnie tak podpisany aplet, przed jego uruchomieniem wyświetli okno z prośbą o akceptację naszego certyfikatu. Stworzenie takiego certyfikatu nie jest trudne, sprowadza się ono do uruchomienia narzędzia keytool, które jest dołączone do SDK (w katalogu jre/bin).


keytool -genkey -alias holowko -storepass holowkosp -keypass holowkokp -keystore holowko.keystore

Po wykonaniu tego polecenia zostanie wygenerowany plik z certyfikatem holowko.keystore (narzędzie poprosi nas najpierw o podanie kilku informacji, takich jak imię, nazwisko, organizacja, lokalizacja itd, zostaną one wyświetlone potem w oknie akceptacji certyfikatu przez użytkownika ). Plik JAR z apletem można ręcznie podpisać, ale ja skorzystałem tutaj z pluginu mavena: maven-jarsigner-plugin.

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-jarsigner-plugin</artifactId>
	<version>1.2</version>
	<executions>
	  <execution>
		<id>sign</id>
		<goals>
		  <goal>sign</goal>
		</goals>
	  </execution>
	</executions>
	<configuration>
	  <keystore>src/main/keystore/holowko.keystore</keystore>
	  <alias>holowko</alias>
	  <storepass>holowkosp</storepass>
	  <keypass>holowkokp</keypass>
	</configuration>
</plugin>

W konfiguracji plugina należy podać tylko ścieżkę do pliku z certyfikatem, która ma zostać wykorzystany, oraz dane dostępu do certyfikatu. Po takiej konfiguracji maven podpisze automatycznie nasz aplet po skompilowaniu projektu i spakowaniu go w plik JAR (polecenie mvn install).

Aby wysłać wiadomość do GWT z apletu, należy wywołać funkcję JavaScript zdefiniowaną wcześniej po stronie GWT. Do komunikacji apletu z JavaScript’em można wykorzystać klasę JSObject, która zapewnia łatwy dostęp do  struktury DOM na stronie oraz umożliwia wywoływanie funkcji JavaScript. Z tej funkcjonalności skorzystamy aby wysłać wiadomość do strony GWT.

	/**
	 * Sends the specified message to GWT App.
	 * @param message
	 */
	private void sendMessageToGwt(String message) {
		System.out.println("sending message to GWT: " + message);
		JSObject window = JSObject.getWindow(this);
		window.call("sendMessageToGwt", new Object[] { message });
	}

W linii 7 pobierany jest obiekt okna, w którym osadzony jest dany aplet. Funkcję JavaScript można wywołać korzystając z metody call (w parametrach podajemy nazwę funkcji do wywołania oraz tablicę argumentów, która zostanie przekazana funkcji w czasie wywołania) na pobranym wcześniej obiekcie JSObject. Aby klasa JSObject była widziana przez nasz aplet należy dodać do zależności bibliotekę JAR, którą możemy znaleźć w każdym JRE w lokalizacji jre/lib/plugin.jar. Ja po prostu wrzuciłem tego JAR’a do lokalnego repozytorium Mavena, a następnie skonfigurowałem odpowiednią zależność w pliku POM projektu apletu.

W celu zapewnienia komunikacji w stronę apletu dodałem prostą metodę w ciele klasy apletu:

/**
 * Invoked from GWT App. Appends the specified message to text area in applet.
 * @param message
 */
public void sendMessageToApplet(String message) {
	System.out.println("message from gwt: " + message);
	StringBuilder sb = new StringBuilder(msgFromGWT.getText());
	sb.append(FORMAT.format(new Date()));
	sb.append(":");
	sb.append(message);
	sb.append("\n");
	msgFromGWT.setText(sb.toString());
}

Tak przygotowany aplet może posłużyć do wbudowania go w aplikację GWT. Całość kodów źródłowych w załączniku. Teraz możemy przejść do budowy projektu aplikacji GWT. Przygotowany wcześniej aplet umieszczamy w zależnościach projektu, lecz aby plik JAR był widoczny przez aplikację należy go umieścić w odpowiednim miejscu. I znów z pomocą przychodzi jeden z pluginów maven’a.

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-dependency-plugin</artifactId>
	<executions>
		<execution>
			<id>copy</id>
			<phase>validate</phase>
			<goals>
				<goal>copy</goal>
			</goals>
			<configuration>
				<outputDirectory>${project.build.directory}/${project.build.finalName}/applets/lib</outputDirectory>
				<artifactItems>
					<!-- SAMPLE APPLET -->
					<artifactItem>
						<groupId>pl.holowko.samples</groupId>
						<artifactId>sample-applet</artifactId>
						<version>1.0</version>
						<type>jar</type>
						<overWrite>true</overWrite>
						<outputDirectory>${project.build.directory}/${project.build.finalName}/applets</outputDirectory>
						<destFileName>sample-applet.jar</destFileName>
					</artifactItem>
				</artifactItems>
			</configuration>
		</execution>
	</executions>
</plugin>

Plik z apletem będzie po prostu kopiowany do folderu „applets” pod nazwą „sample-applet.jar„. Aby umieścić obiekt apletu w aplikacji GWT należy zdefiniować obiekt HTML, w którym zostanie osadzony aplet. Dla różnych przeglądarek taka definicja kodu HTML będzie wyglądać inaczej, dlatego też zdefiniowałem osobną klasę AppletHtml odpowiedzialną za generowanie kodu HTML dla apletu. Stworzyłem dwie implementacje tej klasy, które w zależności od typu przeglądarki są dynamicznie wstrzykiwane poprzez mechanizm późnego wiązania udostępniany przez GWT. Konfiguracja w pliku gwt.xml wygląda następująco:

<replace-with class="pl.holowko.samples.gwt.client.applet.AppletHtml">
	<when-type-is class="pl.holowko.samples.gwt.client.applet.AppletHtml" />
</replace-with>

<replace-with class="pl.holowko.samples.gwt.client.applet.AppletHtmlIE">
	<when-type-is class="pl.holowko.samples.gwt.client.applet.AppletHtml" />
	<when-property-is name="user.agent" value="ie6" />
</replace-with>

W przypadku uruchomienia aplikacji w Internet Explorerze kod HTML będzię wygenerowany przez klase AppletHtmlIE, dla pozostałych przypadków wykorzystana zostanie podstawowa implementacja AppletHtml. Teraz należy zdefiniować funkcję JavaScript, którą aplet będzie mógł wywołać. Skorzystamy tu z JSNI (JavaScript Native Interface):

public native void registerMethodsForApplet(AppletWrapper thisObject) /*-{
	$wnd.sendMessageToGwt = function(message) {
		thisObject.@pl.holowko.samples.gwt.client.applet.AppletWrapper::sendMessageToGwt(Ljava/lang/String;)(message);
	}

}-*/;

public void sendMessageToGwt(String message) {
	onMessageReceivedFromApplet(message);
}

Funkcja „sendMessageToGwt” (linia 2) przekazuje po prostu to co dostanie do konkretnej metody już po stronie Javy. Podobnie w drugą stronę również wykorzystamy JSNI.

private native void invokeSendMessageToApplet(String appletId, String message) /*-{
	$doc.getElementById(appletId).sendMessageToApplet(message);
}-*/;

Zdefiniowana tak metoda pobiera obiekt apletu, któremu nadaliśmy wcześniej unikalne id (obudowując go w HTML), a następnie wywołuje na nim metodę „sendMessageToApplet”.

Cała aplikacja prezentuje się tak jak poniżej. Wiadomości wpisane w poszczególne okienka docierają do siebie bez problemu 🙂

W prezentowanym przykładzie aplet został wbudowany bezpośrednio w strukturę aplikacji GWT, można natomiast go całkowicie schować (zmieniając jego rozmiar do minimum oraz przesuwając w niewidoczne miejsce) i wykorzystywać jego funkcjonalność w tle, poprzez konstrukcję fasady po stronie GWT.

Załączniki

sample-gwt-applet
Filename : sample-gwt-applet-3.zip (20 KB)
Podpis :