Pisanie testów w JavaScript

10/02/2013 Dodaj komentarz

JavaScript potrafi być upierdliwe ;).
Pomijając problem z manipulacja DOM, ciężko się tworzy w tym kod, który możesz od razu sprawdzić czy debgować. Teraz trochę się to zmieniło, porównując to do czasów kiedy zaczynałem się poważniej zajmować JavaScriptem: przykładowo mamy FireBug_a i inne dodatki do przeglądarek, które ułatwiają nam zrozumienie co się dzieje w kodzie.
Jednak problemy typu: brak średnika lub sama literówka w nazwie zmiennej są najczęściej odkrywane w przeglądarce kiedy uruchamiamy daną stronę i widzimy że wyrzucane są wyjątki. Taki błędy odkrywane są powoli.

Rozwiązanie tych problemów może być pisanie testów. Wymaga to jednak pewnego zachodu np. porządku w plikach js, tak aby nie ciągnąć za sobą zbyt dużo zależności. Do końca sam nie wiem jak się do tego dobrze zabrać.
Sposób jaki postaram się tu przedstawić jest dobry do testowania prostych koncepcji lub nauki JavaScriptu.

Wszystko zaczyna się od narzędzia jakim jest js-test-driver. Pod podanym linkiem jest strona tego narzędzia, a na niej filmik prezentujący sposób pracy z nim (polecam go obejrzeć, to co opiszę dalej w dużym stopniu opera się o to co zostało tam pokazane). Używanie tego wymaga pewnego zachodu z ustawieniem środowiska pracy, tak aby testować kod we wskazanych przeglądarkach.

Tutaj jest dobre miejsce do startu, są tu przykładowe testy wraz ze wszystkim co jest potrzebne do uruchomienia, Potrzebne pliki (jary) można jednak pobrać z innego miejsca. Także idąc za podanym przykładem, testy będę pisał w oparciu o ten sam problem „gra w życie” (szczegóły).

Jak uruchomić serwer testów
A więc zaczynajmy od uruchomienia serwera, należy mieć odpowiedni jar (tutaj jest to JsTestDriver-1.3.5.jar). Serwer można uruchomić poniższą komendą:

java -jar JsTestDriver-1.3.5.jar --port 9876

Lub za pomocą skryptu, zawierającą tą komendę. Jest to najprostsza konfiguracja gdzie jedynym istotnym parametrem jest port pod którym będzie dostępny serwer. Po wystartowaniu serwera należy otworzyć przeglądarkę, w której chce się testować (można testować jednocześnie pod kilkoma), i podać adres:

http://localhost:9876

Następnie kliknąć link „Capture This Browser” i przeglądarka jest przechwycona do testów.

Jak uruchomić testy
Testy uruchamia się podobną komendą, choć jest ona trochę bardziej skomplikowana. U mnie upchnięta do pliku bat wygląda tak:

set BASE_DIR=D:\game-of-life
java -jar "%BASE_DIR%\JsTestDriver-1.3.5.jar" ^
--config "%BASE_DIR%\jsTestDriver.conf" ^
--basePath "%BASE_DIR%" ^
--tests all --reset

W podanym przykładzie wszystkie pliki są w tym samym katalogu. Plik jsTestDriver.conf z konfiguracją mówiący o tym co ma być wczytane podczas uruchamiania testów i pod jakim adresem działa serwer testów. Wygląda on tak:

server: http://localhost:9876

load:
- js/jasmine.js
- js/JasmineAdapter.js
- http://underscorejs.org/underscore-min.js
- game-of-life.js
- game-of-life-tests.js

Kończąc ten opis jak uruchomić testy.
Całość kodu jest dostępna tutaj. A sama symulacja życia może być podziwiana tutaj. Fajny sposób do dzielenia się kawałkami kodu ;). Można na żywo edytować i sprawdzać jak zmiany się zachowują. Polecam pobawić się zmianą reguł życia.

Kategorie:Inne Tags: ,

Wyświetlanie nazwy wykonywanej metody

29/01/2013 Dodaj komentarz

Ostatni miałem potrzebę tworzenia wielu (testowych) podobnych metod. Technika kopiuj, wklej i zmiana dla potrzeb danego przypadku. Pierwsza wpis w każdej metodzie to wyświetlenie krótkiej informacji o tym co jest wywoływane. Dawało to informacje o tym co się dzieje w historii wywołań. Metody przybierały postać jak poniżej:

	public void doSomthing1() {
		System.out.println("doSomthing1");
		// ...
	}
	public void doSomthing2() {
		System.out.println("doSomthing2");
		// ...
	}

Tak więc zawsze występowała potrzeba poprawy nazwy w pierwszej linii. Było to trochę uciążliwe, więc wynikła potrzeba wprowadzenia udogodnienia, co poskutkowało takim kodem:

	public void doSomthing3() {
		System.out.println(MethodHelper.getExecutedMethodName());
		// ...
	}

Implementacja tej metody poniżej. Nie jest ona może najpiękniejsza, ale spełnia swoje zadania. Po fakcie w internecie znalazłem wpisy o tym, że nie tylko ja miałem potrzebę posiadania takiej metody.

	public static String getExecutedMethodName() {
		StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
		boolean next = false;
		for (StackTraceElement stackTraceElement : stackTrace) {
			String string = stackTraceElement.getMethodName();
			if (next) {
				return string+" line:"+stackTraceElement.getLineNumber();
			}
			if ("getExecutedMethodName".equals(string)) {
				next = true;
				continue;
			}
		}
		return "Metchod Name Not Found";
	}

Jeszcze na koniec dokonałem pewnego usprawnienia. Dodałem wpis o linii w której jest wykonywane wywołanie ;).
Tak wiec rozpoznanie co się dzieje w kodzie w postaci brutalnego stylu jak poniżej, także jest łatwiejsze

	public void doSomthing3() {
		System.out.println("doSomthing3: 1");
		// some code
		System.out.println("doSomthing3: 2");
		// some code
		System.out.println("doSomthing3: 3");
		// some code
	}

i może wyglądać tak:

	public void doSomthing3() {
		System.out.println(MethodHelper.getExecutedMethodName());
		// some code
		System.out.println(MethodHelper.getExecutedMethodName());
		// some code
		System.out.println(MethodHelper.getExecutedMethodName());
		// some code
	}
Kategorie:Java Tags: ,

Kilka pytań rekrutacyjnych

10/01/2013 Dodaj komentarz

Kilka ciekawych pytań sprawdzających znajomość javy.

StringBuffer vs. StringBuilder
Pytanie może wyglądać tak: jaka jest różnica pomiędzy StringBuffer, a StringBuilder? lub który z nich jest wydajniejszy?

Sprawdzane jest tutaj to czy wie się że StringBuilder jest młodszym bratem StringBuffer (wprowadzony w wersji 1.5) i że główna różnica pomiędzy nimi to brak słowa synchronized przy publicznych metodach w przypadku StringBuilder. Pośrednio z tej wiedzy wynika także odpowiedź na pytanie o wydajności.

Patrząc pobieżnie na projekty w których pracowałem i kod który został użyty do klejenia stringów, to widzę że przewaga jest po stronie StringBuffer ;). Jest tak raczej z przyzwyczajenia, po za tym operacje te nie są krytyczne i jest ich nie wiele. Mam jednak postanowienie na przyszłość: jak powołuje do życia obiekt klasy do klejenia stringów, i ten obiekt zakończy swój żywot w obrębie tego samego bloku kodu (ciała metody) to używać należy StringBuilder, przykład:

  public static String getCustomStackTrace(Throwable aThrowable) {
    final StringBuilder result = new StringBuilder( "StackTrace: " );
    result.append(aThrowable.toString());
    final String NEW_LINE = System.getProperty("line.separator");
    result.append(NEW_LINE);

    //add each element of the stack trace
    for (StackTraceElement element : aThrowable.getStackTrace() ){
      result.append( element );
      result.append( NEW_LINE );
    }
    return result.toString();
  }

Reprezentacja pieniędzy
Pytanie może wyglądać tak: czego byś użył do reprezentacji pieniędzy (np. należności za zamówienie)?. Dalsza wersja tego pytania może być uzasadnienie podanej odpowiedzi.

Mi od razu nasuwa się BigDecimal, jako że od zawsze tego używałem. Robiłem to nie z powodu jakichś głębszych przemyśleń, ale z przyzwyczajenia, że tak powinno być. Jeśli kiedyś znałem jakieś uzasadnienie tego, to ugrzęzło ono w odmentach pamięci ;). Tak też powiedzenie na przykład dlaczego nie float wprowadziło mnie w lekkie zakłopotanie.
Szukając trochę, znalazłem że proste typy numeryczne nie gwarantują poprawności co do oczekiwanego wyniku na operacjach z liczbami zmiennoprzecinkowymi.
Prosty przykład:

		double badValue = 0.33;
		System.out.println(10*badValue);
		
		BigDecimal goodValue = new BigDecimal("0.33");
		System.out.println(goodValue.multiply(BigDecimal.TEN));

I wyniki są następujące:

3.3000000000000003
3.30

Co ciekawe jeśli zainicjujemy BigDecimal trochę inaczej (nie jako string, ale przekazując prosty typ):

		BigDecimal goodValue = new BigDecimal(0.33);
		System.out.println(goodValue.multiply(BigDecimal.TEN));

to możemy otrzymać coś takiego:

3.300000000000000155431223447521915659308433532714843750

Więc i tu też może być haczyk ;). Ale główna wiedza jaka jest sprawdzana przez takie pytanie to świadomość o możliwości utracie precyzji przy wykorzystaniu prostych typów (tutaj też znalazłem fajne streszczenie tego).

Działanie equals() i hashCode()
Pytania tutaj mogą być przeróżna, ale ich cel to sprawdzenie czy ktoś rozumie po co są te metody i jak je używać.

Jak dla mnie pierwsze ze skojarzeń jakie mam z tym to pamiętanie o tym aby zaimplementować je w tworzonej klasie jeśli chce się przechowywać obiekty tej klasy w kolekcjach. Wiedząc o tym, przy tworzeniu nowej klasy, uruchamiamy odpowiedni skrót w IDE i otrzymuję wygenerowane metody. I na tym może się kończyć nasz refleksja nad sensem tych metod, co też może prowadzić do zdziwień w przykładach jak poniżej.

Załóżmy, że mamy klasę, w których implementacja tych metod są takie że: equals zwraca zawsze false, a hashCode zawsze 1 (to budzi lekkie zdziwienie po co tworzyć takie coś, ja sam nie znajduję sensownej przyczyny robienia czegoś takiego ;)). Idźmy dalej: powiedzmy że klasa ta to Person i w konstruktorze przyjmuję pojedynczą wartość String, będącą nazwą danej osoby.
Tak więc tworzymy trzy instancje tej klasy dwie z argumentem „Jan”, jednak z „Tomasz” i dodajemy jej do kolekcji typu HashSet. Pytanie jest, ile obiektów jest w kolekcji?.
Jest to pytanie na zrozumienie zasad stosowania tych dwóch metod. Wiedza ta jest tu sprawdzana trochę w zagmatwany sposób. Tym się usprawiedliwiam :), bo gdy usłyszałem to pytanie w takiej postaci udzieliłem złej odpowiedzi. Wychodząc z założenia, że w kolekcjach typu Set nie może być duplikatów, twierdziłem że będzie tylko jeden „Jan” w towarzystwie „Tomasz”. Ignorując zupełnie fakt, że nadpisałem metodę equals, które mówi mi o tym czy dany obiekt znajduję się już w kolekcji. Zakładając bez większego zastanowienia że słówka hash w HashSet gra tu istotną role i próbowałem strzelać co do odpowiedzi bez większego namysłu. Podczas gdy hashCode zadecyduje tylko o rozkładzie w „kubełkach” tej kolekcji (a właściwie tylko w jednym „kubełku” co zapewniliśmy sobie pisząc w taki sposób metodę hashCode), a equels zadecyduję i tak czy dany obiekt jest duplikatem.
Kończę usprawiedliwianie swojej pomyłki: podane przykład powinien mieć pomocnicze pytanie (lub samemu powinno się je zadać sobie): dlaczego taka implementacja equals i hashCode jest błędna?

Kategorie:Java Tags:

Dysonans poznawczy

28/08/2012 Dodaj komentarz

Dysonans poznawczy to ciekawy termin na który ostatnio wpadłem. Link jest lepszym źródłem wiedzy, więc dalej przytoczę do czego może wydawać się to użyteczne.

Wyrywkowo jednak aby skupić się na tym o co mi chodzi to: „Teoria dysonansu poznawczego postuluje, że gdy w sytuacji wolnego wyboru postępujemy niezgodnie z naszymi postawami, to postawy zostaną dostosowane do naszych zachowań. Ludzie myślą tak, aby to było zgodne z ich zachowaniem”. Lub inaczej człowiek stara się redukować stany w którym odczuwa że „Co innego myślę, a co innego robię”.

A co do wykorzystania tego. W oparciu o założenia tej teorii był wykonany eksperyment, w skrócie było to tak: Poproszono studentów o wzięcie udział w pogadance dla liceistów na temat korzyści z używania prezerwatyw. Później stwierdzono że wśród tych studentów wzrost poziom użycia prezerwatyw.
Tak więc przeszczepiając to na grunt informatyczny: jeśli ktoś wystąpi z prezentacją w której mówi na przykład o zaletach stosowania TDD, podczas gdy nie do końca jest o tym przekonany, to może to skutkować tym że w późniejszym okresie będzie częściej stosować tą technikę ;). Tak jakby tłumaczył się, że w końcu zachwalałem to publicznie, to trudniej jest mu postępować inaczej później. Takie zachowanie wprowadzające dysonans nie musi sprowadzać się do prezentacji, może to być wpis na blogu lub podpisanie ankiety popierającej coś (na przykład w takiej formie).
W każdym razie przy pomocy takiego triku można chyba promować zachowania, które się pożąda, jeśli inne wydawałoby się racjonalne argumenty zawiodły ;).

Kategorie:Inne Tags: ,

Jak szybko stworzyć aplikacje webową, która zwraca JSON-a

16/07/2012 Dodaj komentarz

Ostatnio sprawdzałem możliwości JavaScriptu w aplikacjach webowych. Tutaj udział część serwerowej sprowadzał się do obsługi wywołań AJAX-owych (zwracania wyników w JSON-e). W skrócie nie chciałem się zajmować serwerem, wystarczało że zwracał mi jakiś kawałek JSON-a, tak abym mógł skupić się tylko na HTML, CSS i JS.

Bez Javy, ale tak bym chciał
Tak więc na początek trafiłem na takie całkiem fajne rozwiązanie w pythonie.

python -m SimpleHTTPServer 8080

Jak ma się zainstalowanego pythona, to jest to najprostszy sposób na postawienie serwera HTTP. Gdzie wystawioną zawartością, poprzez URL, jest to co znajduje się w katalogu, w którym z linii poleceń uruchomiło się to. Tak więc jeśli mamy tam katalog
dane, a w nim plik test.json, to możemy do tego pliku odwołać się poprzez taki url:

http://localhost:8080/dane/test.json

Zatem statyczne kawałki JSON-a leżą sobie w plikach na dysku, obok może znajdować się plik app.js, który odwołuję się do nich, i który to jest głównym przedmiotem pracy. Całość mogę edytować po dowolnym narzędziem, i każda zmiana od razu jest widoczna w przeglądarce (wystarczy F5). Piękne 🙂 nie trzeba się martwić synchronizacją z serwerem, można się skupić na pracy i od razu widzieć efekty w przeglądarce.
Rozwiązanie to daje jednak tylko statycznego JSON-a. Aby wprowadzić więcej dynamizmu trzeba jednak napisać trochę po stronie serwera. Nie patrzyłam już czy SimpleHTTPServer oferuję jakieś większe możliwość przeszedłem od razu do javy, w końcu jak na razie w tym głównie piszę.

Z Javą, próba odtworzenia
Zacząłem od stworzenia prostego projektu mavenowego, tak aby móc łatwo zarządzać zależnościami, po za tym i tak zwykle jest to projekt tego typu. Idą za wskazówkami zawartymi w tym poście wybrałem SpringMVC. Cała moja praca po stronie serwera ograniczyła się do stworzenia jednej klasy, która produkowała mi JSON-a jakiego chciałem.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/app")
public class AppController {
	
	private static List<String> names = new ArrayList<String>();
	
	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public @ResponseBody void add(@RequestParam(value="name") String name){
		names.add(name);
	}
	
	@RequestMapping(value = "/listAll", method = RequestMethod.GET)
	public @ResponseBody List<String> listAll(){
		return names;
	}
	
	@RequestMapping(value = "/remove", method = RequestMethod.GET)
	public @ResponseBody void remove(@RequestParam(value="name") String name){
		names.remove(name);
	}

}

Dzięki temu dostałem trzy url-e, z których mogłem korzystać po stornie JavaScript:

http://localhost:8080/RestTest/rest/app/add?name=dwa
http://localhost:8080/RestTest/rest/app/remove?name=dwa
http://localhost:8080/RestTest/rest/app/listAll

Ostatni może zwracać takiego JSON-a:

["jeden","dwa","trzy"]

Takie coś w zupełności wystarcza do symulowania logiki po stronie serwera, a jak widać w przedstawionej klasie, rozbudowanie tego nie powinno być trudne.
Oprócz tej klasy potrzebne były jeszcze techniczne pliki, wszytko wziąłem z projektu w przytoczonym poście.
Tak wiec w web.xml potrzebne są takie wpisy aby postawić kontekst Springa.

	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

Najistotniejsze jest zwrócenie skąd się bierze rest w URL (RestTest to nazwa mego wara), a plik mvc-dispatcher-servlet.xml opisujący co Spring ma robić jest trywialny:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

	<context:component-scan base-package="test.controller" />

	<mvc:annotation-driven />

</beans>

jak widać jedyne co trzeba dodać to wpis włączający interpretacje adnotacji w napisanej klasie. Do dopełnienie wszystkiego jest jeszcze plik mavena, który zaprezentuje na końcu.

Jest Java, ale jakby krok wstecz
Tak więc miałem już dynamicznego JSON-a, i sposób jak go dostosowywać. Mogłem się zabrać za JavaScript. Jednak utraciłem tutaj szybką pętle zwrotną, w weryfikacji wprowadzanych zmian. Teraz pomiędzy zapisaniem zmiany w pliku, a odświeżeniem widoku w przeglądarce, doszedł krok budowy wara i wgrania go na Tomcata lub inny WebSerwer. A ja chciałem tylko zmieniać pliki JS lub HTML, część serwerowa nie zmieniałaby się w ogóle.

Z Javą, już prawie idealnie
Rozwiązań tego pewnie jest parę. Ja zwróciłem się w kierunku wbudowanego kontenera aplikacje webowych, czyli użyłem jetty.
W pom.xml pojawia się taki wpis jak niżej. Jetty uruchamia się taka komendą mvn jetty:run.

			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
				<version>6.1.24</version>
				<configuration>
					<stopPort>9966</stopPort>
					<stopKey>RestTest</stopKey>
					<!-- Redeploy every x seconds if changes are detected, 0 for no automatic redeployment -->
					<scanIntervalSeconds>0</scanIntervalSeconds>
					<!-- make sure Jetty also finds the widgetset -->
					<webAppConfig>
						<contextPath>/RestTest</contextPath>
						<!-- -->
						<baseResource implementation="org.mortbay.resource.ResourceCollection">
							<resources>src/main/webapp</resources>
						</baseResource>
					</webAppConfig>
				</configuration>
			</plugin>

Ważny jest parametr scanIntervalSeconds, mówi on o tym czy zmiany w naszych klasach będą automatycznie redeployowane. Trwa to trochę, ale można z tym żyć. To i tak nie dotyczy naszego HTML-a i JS, to co powoduję że zmiany w tych plikach są widoczne od razu w przeglądarce, to parametr baseResource. Wskazanie na katalog webapp, gdzie trzymane są te pliki powoduje, że zmiany są propagowane (wykomentowałem ten parametr i funkcjonalność ta nadal działało co pewnie świadczy o tym że jest to wartość domyśla). Nie wczytywałem się za bardzo w szczegóły ustawień i może trochę podorabiałem teorii do praktyki, ale działa tak jak chciałem. Mam co chciałem i mogę spokojnie pracować nad plikami JS, i zmiany w nich widzieć od razu w przeglądarce.

Taki mały zgrzyt
Pojawia się zgrzyt, podobno tylko dla Windowsa, pliki uaktualniają się tylko za pierwszym razem, kolejny raz nie można już zapisać, bo są blokowane. Ten wpis opisuje problem i możliwe rozwiązania. Ja użyłem dodatkowego wpisu w web.xml, na razie nie martwię się tym że brudzi to ten plik. Dodatkowy element to:

	<servlet>
	    <servlet-name>default</servlet-name>
	    <servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class>
	    <init-param>
	      <param-name>useFileMappedBuffer</param-name>
	      <param-value>false</param-value>
	    </init-param>
	    <load-on-startup>0</load-on-startup>
	  </servlet>

I to wszytko, można się zabrać za JavaScript. Teraz mam szybką odpowiedź zwrotną w przeglądarce, wiec jak dla mnie bardzo dobre warunki do pracy z tak krnąbrny językiem 😉 , o czym może napisze następnym razem.

A całość pom.xml prezentuję się tak:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>test</groupId>
	<artifactId>RestTest</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<spring.version>3.0.5.RELEASE</spring.version>
	</properties>

	<dependencies>

		<!-- Jackson JSON Mapper -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.7.1</version>
		</dependency>
		<!-- Spring 3 dependencies -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

	</dependencies>

	<build>
		<finalName>RestTest</finalName>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
				<version>6.1.24</version>
				<configuration>
					<stopPort>9966</stopPort>
					<stopKey>RestTest</stopKey>
					<!-- Redeploy every x seconds if changes are detected, 0 for no automatic 
						redeployment -->
					<scanIntervalSeconds>0</scanIntervalSeconds>
					<!-- make sure Jetty also finds the widgetset -->
					<webAppConfig>
						<contextPath>/RestTest</contextPath>
						<!-- -->
						<baseResource implementation="org.mortbay.resource.ResourceCollection">
							<resources>src/main/webapp</resources>
						</baseResource>
					</webAppConfig>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

Małe uaktualnienie: taki sam efekt z wbudowanym kontenerem aplikacji webowych można uzyskać z tomcat-maven-plugin. Nie ma się tylko przeładowania klas (w każdym razie nie znalazłem tego). Ale nie trzeba brudzić swego pliku web.xml i nie ma problemu z blokowaniem edytowanych plików. Tak więc w pomie zamiast jetty należy dodać:

			
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>tomcat-maven-plugin</artifactId>
				<version>1.1</version>
			</plugin>

i uruchomić z linii poleceń komendą: mvn tomcat:run

Małe narzędzie do przetwarzania plików

31/03/2012 Dodaj komentarz

Przetwarzanie plików, ich zawartość, tak aby na ich podstawie stworzyć coś innego.
Najczęściej jeśli pliki są niewielkie robi się to ręcznie. Jeśli są trochę większe to można zaprzęgnąć do tego jakieś dobry edytor tekstu. A czasem trzeba napisać narzędzie do tego.
Poniżej zamieszczam prosty skrypt do przetwarzania plików, będzie służył jako baza do tworzenia podobnych narzędzi w przyszłości.

print "start"

class Paczka:
    tabela = ''
    nazwa = ''
    kolumna = ''

    def build(self):
        return 'CREATE INDEX '+self.nazwa+' ON '+self.tabela+' ('+self.kolumna+');'

file = open('indeksy.txt','r+')
data = file.readlines()
file.close()

paczka = Paczka()
for line in data:
    if ("Foreign Key:" in line):
        paczka.nazwa = line.split("Foreign Key:")[1].strip()
    if ("On Table:" in line):
        paczka.tabela = line.split("On Table:")[1].strip()
    if ("Columns:" in line):
        paczka.kolumna = line.split("Columns:")[1].strip()
    if ("Columns:" in line):
        print paczka.build()
        paczka = Paczka()

print "koniec"

Jak można wyczytać program ma wyprodukować zbiór instrukcji tworzących indeksy. Robi to na podstawie pliku, zawierającego wskazania w których miejscach można poprawienia wydajności bazy. Przykład poniżej:

! Foreign Key: SCHEMAT.FK_TABELA_1
!   On Table:  TABELA_1
!   Columns:   KOLUMNA_1

! Foreign Key: SCHEMAT.FK_TABELA_2
!   On Table:  TABELA_2
!   Columns:   KOLUMNA_3

! Foreign Key: SCHEMAT.FK_TABELA_3
!   On Table:  TABELA_3
!   Columns:   KOLUMNA_3

Program jest prosty, widać co jest robione. Usprawnienie co do pierwotnej wersji to wydzielenie klasy agregującej dane. Daje to odseparowanie togo co ma powstać od etapu przetwarzania pliku. Można by się pokusić jeszcze o uogólnienie kodu przetwarzającego poszczególne linie (pozbycie się if_ów). Jednak w tym przypadku byłby to już przerost formy nad tym co ma być wykonane. Może kiedyś uaktualni się ten wpis.

Kategorie:Inne Tags: , ,

log4j z WebSpherem

08/02/2012 Dodaj komentarz

Krótki opis przypadku (frustracji).

Problemy z uruchomieniem logowania na WebSperze (dokładnie to WAS 6.1, ale to chyba mało istotne).

Objawy
Użycie standardowej konfiguracji log4j nie daje spodziewanego efektu. Logi się nie odkładają, mimo że analogiczna aplikacji osadzona np. na JBossie zachowuję się poprawnie.

Rozwiązanie
Pomocny okazał się ten wpis.
Za umieszczonym tam opisem zrobiłem tak:
1. Stworzyłem plik commons-logging.properties i umieściłem go w katalogu WEB-INF\classes (war). Zawartość taka sama jak w przytaczanym wpisie.

priority=1
org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

2. Następnie na WASie w opcjach konfiguracji aplikacji; w opcji zarządzania ładowanie klas zaznaczyłem obie opcje odwrotnie niż to było domyślnie. Głównie chodzi o ładowanie najpierw klas aplikacji z wara. Zrzut konfiguracji poniżej.

Po tych zabiegach logowanie zaczęło działać tak jak chciałem.

Może to pomoże komuś innemu. Choć podejrzewam że rozwiązanie nie zawsze będzie dokładnie takie same. Jednak przynajmniej da to pojęcie gdzie szukać.

Kategorie:Java Tags: ,