Archiwum

Posts Tagged ‘narzedzia’

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

Reklamy

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 Tagi: , ,

Social coding

02/02/2012 Dodaj komentarz

Tytuł jest trochę naciągany, ale w pewien sposób oddaję to co opiszę poniżej.

Lubię przeglądać cudzy kod ;). Tak bez szczególnego celu. Może to być w formie śledzenia (podczas synchronizowania się) tego co zostało wkomitowane przez kolegów w pracy; czy przeglądania kodu projektów dostępnych w sieci. Często można zaleźć coś ciekawego, co zmusi do zastanowienia i w rezultacie pozwoli na odkrycie ciekawej biblioteki czy konstrukcji w kodzie.

Szczególnym przypadkiem jest przeglądanie plików pom.xml, wymaganych przez mavena. Zawiera się tu techniczny (ogólny) opis danego projektu: to jakie bibliotek czy pluginy zostały w nim użyte. Można zobaczyć co jest stosowane w podobnych przypadkach, z jakimi się stykamy, i dzięki temu odkryć coś użytecznego, np. wspominane już biblioteki.

I tutaj rodzi mi się pomysł na udział społeczności. Fajnie byłoby mieć narzędzia, które na podstawie pom, mojego aktualnego projektu, przeszuka sieci pod kątem innych pomów dostępnych gdzieś tam. Wynikiem tego przeszukania mógłby być wykaz potencjalnych bibliotek, którymi mógłbym być zainteresowany. Coś w stylu tego co ma np. amazon: propozycji książek którymi mógłbym być zainteresowany. Tutaj brzmiałby to tak: użytkownicy biblioteki X i Y stosowali także bibliotek Z – może warto się nią zainteresować.

Pliki pom są tworzone w ustalonym formacie dlatego też napisanie parsera który przeszedłby po wszystkim co znajdzie i zebrał statystyki nie powinno być trudne. Tak samo osoby dostarczające swoje pom_y (przyjmując że jest to jakiś serwis dostępny globalnie), jako kryterium zapytania, powodowałyby że poziom dostępnych statystyk rósł by.
Statystyki taki naturalnie nie dostarczą precyzyjnej wiedzy, ale pomogą rzucić światło na panujący trend.

Działania takiego narzędzia wyznaczają nawyki użytkowników. W moim przypadku jest to przeglądanie pom_ów i na podstawie tego decydowanie jaką bibliotek poznać bliżej. Mogą być inne zachowania związane z przeglądaniem kodu, które można sformalizować i spróbować zatrudnić do tego komputer. Na pewno nie otrzymamy tu wyczerpującego sprawozdania, ale coś co pozwali nam ułatwić choć trochę życie ;).

Kategorie:Java Tagi: , ,

Ćwiczenie z wariacją

09/12/2011 Dodaj komentarz

Ten filmik (budzi podziw :)) zainspirował mnie do wykonania pewnego ćwiczenia. Polegało ono na odgadnięciu tego samego, ale przy pomocy komputera – zadanie jak z pierwszego roku studiów, ale potrafi przynieść satysfakcje.
W poniższej implementacji została użyta brutalna siła :). Generowane są zbiory możliwych kombinacji działań matematycznych (wariacja z powtórzeniami) i każdy z nich jest sprawdzany we wszystkich konfiguracjach danych liczb 😉 (wariacja bez powtórzeń). Po przeliczeniu, ponad 2 milionów przypadków, otrzymałem 8 sposobów na dojście do tej liczby (tak na prawdę były 2, reszta wynikała z przemienności mnożenia). Jeden ze sposobów, inny niż na filmie, to:
(3 + 100) = 103,
(103 * 6) = 618,
(618 * 75) = 46350,
(46350 / 50) = 927,
(927 + 25) = 952

Kod realizujący to sprowadzał się do:

		BigDecimal expected = new BigDecimal(952);
		
		String[] allowedOperations = {Value.ADD, Value.MULTIPLY, Value.SUBTRACT, Value.DIVIDE, Value.DIVIDE2};
		Integer[] givenValues = {25,50,75,100,3,6};
		
		long operationCount = 1;
		long expectedCount = 0;
		for (String[] operations : Permutation.variationWithRepetition(5, allowedOperations)) {
			for (Integer[] values : Permutation.variationWithoutRepetition(6, givenValues)) {
				// wykonanie dzialania
				Value value = Value.value(values[0]);
				for (int j = 0, k = 1; j < operations.length; j++,k++) {
					value = value.compute(operations[j], values[k]);
				}
				// drukuj jesli oczekiwana
				if (expected.equals(value.value)){
					expectedCount++;
					System.out.println(value.computation);
					System.out.println(operationCount);
				}
				operationCount++;
			}
		}

		System.out.println(operationCount);
		System.out.println(expectedCount);

Gdzie klasa Value pozwalająca na zapisywanie działań w taki sposób:

Value value = value(5).compute(MULTIPLY,5).compute(SUBTRACT, 5).compute(DIVIDE, 2);

Wygląda tak:

public class Value {
	
	public static final String DIVIDE = "divide";
	public static final String DIVIDE2 = "divide2";
	public static final String MULTIPLY = "multiply";
	public static final String SUBTRACT = "subtract";
	public static final String ADD = "add";

	public final BigDecimal value;
	public final String computation;
	
	private Value(BigDecimal value, String computation) {
		this.value = value;
		this.computation = computation;
	}
	
	public static Value value(int value){
		return new Value(new BigDecimal(value),""+value);
	}

	public static void main(String[] args) {
		System.out.println("Test: "+Value.class.getSimpleName());
		
		Value value = value(5).compute(MULTIPLY,5).compute(SUBTRACT, 5).compute(DIVIDE, 2);
		
		System.out.println(value.computation);
		System.out.println(value.value);
	}

	public Value compute(String operation, int i) {
		if (this.value == null){
			// nie mozna wyknywac operacj, poprostu zwroc orginal
			// pozwala na unikniecie NPE w trakcie przetwarzania łańcucha
			return this;
		}
		BigDecimal eval = null; 
		BigDecimal value2 = new BigDecimal(i);
		String evalStrin = "";
		
		if (ADD.equals(operation)){
			
			eval = this.value.add(value2);
			evalStrin = evalStrin(this.value, "+" ,value2);
			
		} else if (SUBTRACT.equals(operation)){
			
			eval = this.value.subtract(value2);
			evalStrin = evalStrin(this.value, "-" ,value2);
			
		} else if (MULTIPLY.equals(operation)){
			
			eval = this.value.multiply(value2);
			evalStrin = evalStrin(this.value, "*" ,value2);
			
		} else if (DIVIDE.equals(operation)){
			if(BigDecimal.ZERO.compareTo(value2) != 0){
				eval = this.value.divide(value2, MathContext.DECIMAL32);
			} 
			evalStrin = evalStrin(this.value, "/" ,value2);
			
		} else if (DIVIDE2.equals(operation)){
			if(BigDecimal.ZERO.compareTo(this.value) != 0){
				eval =  value2.divide(this.value, MathContext.DECIMAL32);
			} 
			evalStrin = evalStrin(value2, "/" ,this.value); // odwrocenie
			
		}
		String computation = this.computation + "; "+ evalStrin + " = " + eval;
		Value v = new Value(eval, computation);
		return v;
	}
	
	private static String evalStrin(BigDecimal v1,String operation, BigDecimal v2){
		return "( "+v1 + " "+operation+" " + v2+" )";
	}
	
}

Klasa Permutation, generująca zbiory, została zamieszczona na końcu.

Wnioski z tej zabawy
Fajnie jest czasem pomyśleć nad innymi problemami niż te z którymi ma się zwyczajowo styczność.

Kawałek kodu do generowania możliwych zbiorów pewnie kiedyś się jeszcze przyda. Pierwsze co przychodzi do głowy to generowanie haseł :), ale pewnie są bardziej życiowe przykłady. Chociaż trochę dziwne że nie można czegoś takiego dla javy łatwo znaleźć (może w jakichś matematycznych bibliotekach), dla pythona od razu znalazłem przykład.

Ciekawym pomysłem byłoby aby w generatorze zbiorów dać możliwość sterowania kolejnością zwracanych rezultatów. Tak aby zbiory z wieloma powtórzeniami (*,*,*,*,*) były zwracane na końcu, podczas gdy zróżnicowane w miarę na początku (+,*,*,-,/). Jakoś powinno da się ustawić pożądaną kolejność zwracania zbiorów dla danej klasy problemu, ten facet z filmiku pewnie musi tak robić :).

Można stracić dużo czasu na cyzelowanie implementacji. Zwłaszcza było tak w przypadku Permutation. Kod dający rozwiązanie powstał w jakieś 4 godzin, a zabawa z nim aby go poprawić (przyspieszyć i zrobić bardziej czytelnym) odwlekła się w czasie o jakiś miesiąc ;). I tak nie jest to piękne, ale najgorszy bałagan jest na samym dole. Ciekawe czy tak praca zwróci się w postaci łatwego zrozumienia o co tu biega, jak za jakiś czas wrócę do tego kod.

public class Permutation {

	public static void main(String[] args) {
		int count = 1;
		long start = System.currentTimeMillis();
		for (Integer[] intSet : variationWithoutRepetition(6, new Integer[] { 25, 50, 75, 100, 3, 6 })) {
			System.out.println(Arrays.toString(intSet) + " - " + (count++));
		}
		System.out.println("Czas = " + (System.currentTimeMillis() - start));
	}

	public static <E> Iterable<E[]> variationWithoutRepetition(final int wordLength, final E ... values) {
		return new Iterable<E[]>() {
			public Iterator<E[]> iterator() {
				return new Variation<E>(
						new UpdateContextWithoutRepetition(values.length, wordLength) 
						, values);
			}
		};
	}
	public static <E> Iterable<E[]> variationWithRepetition(final int wordLength, final E ... values) {
		return new Iterable<E[]>() {
			public Iterator<E[]> iterator() {
				return new Variation<E>(
						new UpdateContextWithRepetition(values.length, wordLength)
						, values);
			}
		};
	}
	
	private static class Variation<E> implements Iterator<E[]>  {
		E[] dictionery = null;
		UpdateContext conetxt;
		
		private Variation(UpdateContext conetxt, E ... dict) {
			this.dictionery = dict;
			this.conetxt = conetxt;
		}

		@Override
		public void remove() {
		}
		
		@Override
		public boolean hasNext() {
			return  conetxt.hasNext();
		}

		@Override
		public E[] next() {
			return remapToDictionery(conetxt.nextWord());
		}

		private E[] remapToDictionery(int[] currentIndex) {
			E[] nextWord = create(currentIndex.length);
			for (int i = 0; i < currentIndex.length; i++) {
				nextWord[i] = dictionery[currentIndex[i]];
			}
			return nextWord;
		}

		private E[] create(int length) {
			Class<?> componentType = this.dictionery[0].getClass();
			@SuppressWarnings("unchecked")
			E[] newInstance = (E[])java.lang.reflect.Array.newInstance(componentType, length);
			return newInstance;
		}
		
	}
	
	abstract static class UpdateContext {
		int dictioneryLength;
	    int[] currentIndexWord;
		long finishCount;
		long count = 0;
		int startFromLastIndex;
		private int currentIndex;
		
		public UpdateContext(int dictioneryLength, int wordLength) {
			this.dictioneryLength = dictioneryLength;
			
			this.finishCount = this.finishCount(wordLength);
			this.startFromLastIndex = wordLength - 1;
		}
		
		public boolean hasNext() {
			return (finishCount != count);
		}
		
		public int[] nextWord() {
			if (this.currentIndexWord == null){ // start
				this.currentIndexWord = this.createStartIndexWord();
			} else {
				updateIndex(startFromLastIndex);
			}
			count++;
			return this.currentIndexWord;
		}
		
		private void updateIndex(int lastLetterInWordToChangeIndex) {
			updateCurrentIndex(lastLetterInWordToChangeIndex);
			if (isLastPosibleWord()) {
				// ostatni mozliwy index
				// ustaw na poczatek i zwieksze w poprzedzajacym
				if (lastLetterInWordToChangeIndex > 0) {
					updateIndex(lastLetterInWordToChangeIndex - 1);
				}
				// po powrocie z rekurencyjnego wywolania uaktualnij kontekst
				updateCurrentIndex(lastLetterInWordToChangeIndex);
				setLettet(getFirstPosibleLetter());
			} else {
				setLettet(getNextPosibleLetter());
			}
		}
		
		public void updateCurrentIndex(int currentIndexValue){
			currentIndex = currentIndexValue;
			update(currentIndex);
		}
		public boolean isLastPosibleWord() {
			return currentIndexWord[currentIndex] == getLastPosibleLetterInWord();
		}
		public int getNextPosibleLetter(){
			return getNextPosibleLetterForGivenIndex(currentIndex);
		}
		public int getFirstPosibleLetter() {
			return firstPosibleLetter();
		}
		public void setLettet(int letter){
			currentIndexWord[currentIndex] = letter;
		}
		
		protected abstract int firstPosibleLetter();

		protected abstract int[] createStartIndexWord();

		protected abstract int getNextPosibleLetterForGivenIndex(int lastWordToChangeIndex);

		protected abstract void update(int lastWordToChangeIndex);

		protected abstract long finishCount(int dictLength);
		
		protected abstract int getLastPosibleLetterInWord();
	}
	
	private static class UpdateContextWithoutRepetition extends UpdateContext {
		
		int[] letterThatCanBeUsed;

		public UpdateContextWithoutRepetition(int dictioneryLength, int wordLength) {
			super(dictioneryLength, wordLength);
		}
		@Override
		public int firstPosibleLetter(){
			return letterThatCanBeUsed[0];
		}
		@Override
		public int getLastPosibleLetterInWord(){
			return letterThatCanBeUsed[letterThatCanBeUsed.length - 1];
		}
		@Override
		public int getNextPosibleLetterForGivenIndex(int lastWordToChangeIndex){
			int letterIndexInPosibleWords = findItPositionInArray(this.currentIndexWord[lastWordToChangeIndex], letterThatCanBeUsed);
			return letterThatCanBeUsed[letterIndexInPosibleWords+1];
		}
		
		private static int findItPositionInArray(int it, int[] array){
			for (int i = 0; i < array.length; i++) {
				if(array[i] == it){
					return i;
				}
			}
			return -1;
		} 
		
		@Override
		protected void update(int lastWordToChangeIndex) {
			this.letterThatCanBeUsed = getLetterThatCanBeUsed(lastWordToChangeIndex, currentIndexWord);
		}
		
		@Override
		public int[] createStartIndexWord() {
			return createRange(0, dictioneryLength);
		}
		
		private static int[] createRange(int start, int to){
			int[] range = new int[to - start];
			for (int i = 0; i < range.length; i++) {
				range[i] = i+start;
			}
			return range;
		}
		
		private int[] getLetterThatCanBeUsed(int lastWordToChangeIndex, int[] indexWord) {
			int[] arrayCopyFristValuesToGivenIndex = copyToGivenIndex(indexWord,lastWordToChangeIndex);
			int[] letterThatCanBeUsed = subtractFromRange(arrayCopyFristValuesToGivenIndex);
			return letterThatCanBeUsed;
		}
		
		private static int[] copyToGivenIndex(int[] remove, int toIndex) {
			int[] dest = new int[toIndex];
			System.arraycopy(remove, 0, dest, 0, dest.length);
			return dest;
		}
		
		private int[] subtractFromRange(int[] toRemove) {
			int[] range  = createRange(0, dictioneryLength);
			int resultSize = range.length - toRemove.length;
			if (resultSize == 0) {
				return range;
			}
			int[] result = new int[resultSize];
			
			int signeAsToRemove = -1; // value not in range
			for (int asIndexInRaneg : toRemove) {
				range[asIndexInRaneg] = signeAsToRemove; 
			}
			
			int index = 0;
			for (int valueFromRange : range) {
				if (valueFromRange != signeAsToRemove){
					result[index++] = valueFromRange;
				}
			}
			
			return result;
		}
		
		@Override
		public long finishCount(int dictLength){
			return factorial(dictioneryLength) / factorial(dictioneryLength - dictLength);
		}
		
		private static long factorial(int value) {
			long accumulator = 1L;
			for (long counter = value; ! (counter == 0); counter--) {
				accumulator = (counter * accumulator);
			}
			return accumulator;
		}
		
	}
	
	private static class UpdateContextWithRepetition extends UpdateContext {
		public UpdateContextWithRepetition(int dictioneryLength, int wordLength) {
			super(dictioneryLength, wordLength);
		}
		@Override
		public int firstPosibleLetter() {
			return 0;
		}
		@Override
		public int getLastPosibleLetterInWord() {
			return dictioneryLength - 1;
		}
		@Override
		public int getNextPosibleLetterForGivenIndex(int lastWordToChangeIndex) {
			return this.currentIndexWord[lastWordToChangeIndex] + 1;
		}
		@Override
		protected void update(int lastWordToChangeIndex) {
			// nic nie trzeba robic
		}
		@Override
		public long finishCount(int dictLength){
			return (long)Math.pow(dictioneryLength, dictLength);
		}
		@Override
		public int[] createStartIndexWord() {
			int[] startWord = new int[dictioneryLength];
			for (int i = 0; i < startWord.length; i++) {
				startWord[i] = 0;
			}
			return startWord;
		}
		
	}
	
}
Kategorie:Java Tagi: ,

Wzbogacenie debugu w IDE

24/10/2011 Dodaj komentarz

Przyszedł mi do głowy pomysł na wzbogacenie możliwości pracy w trybie debuge w mym IDE. Pracuje w eclipsie, ale wydaje mi się że rozwiązanie to nie będzie zawężone tylko do tego produktu.
Zacznijmy od nawyku jaki mam w pracy w tym trybie. Wiem że istniej widok „Variables”, w którym mogę przeglądać zmienne będące w aktualnym kontekście. Wiem też o istnieje widoku „Expressions”, w którym mogę wykonywać poszczególne kawałki kodu. Jednak przeglądanie zmiennych nie zawsze daje to co się chcę, a edytowanie kodu w widok „Expressions” nie jest wygodnie.
Dlatego też często stosuje taki coś: Stojąc w pułapce, pisze kod bezpośrednio w tym miejscu gdzie się zatrzymałem. Mam dzięki temu zapewnione wszystkie udogodnienia w edycji kodu. Nie zapisuje pliku więc, taki kod nic nie przeszkadza, i tak zostanie zaraz usunięty. Kod ten następnie wykonuję poprzez zaznaczenie go i wybór z menu kontekstowego „Inspect” (skrót Ctrl + Shift + I).
Jak widać na załączonym obrazku: można wykonać nawet coś co jest komentarzem.

Teraz przechodzę do pomysłu.
Skoro mogę wykonać kod w ten sposób, i wykonując to mam dostęp do całego obecnego kontekstu, to mogę w tym miejscu podpiąć się z jakimś kodem narzędziowym. Kod taki może mi udostępnić informacje jaki moje IDE nie jest w stanie. Mogę na przykład: wyświetlić bardziej precyzyjne informacje o istniejącym grafie obiektów. Mogę też ten obiekt zapisać do pliku i powołać go do życia podczas testów. Mogę także wstrzyknąć swój obiekt, który zbierze jakieś diagnostyczne informacje.
Szybka implementacja narzędzia do zrzutu obiektu do pliku przy użyciu xstream może wyglądać tak:

	public static void storeToFile(Object object) throws IOException {
		XStream stream = new XStream();
		stream.toXML(object, WriterFactory.newXmlWriter(new File("temp.xml")));
	}

	public static Object restoreFromFile() throws IOException {
		XStream stream = new XStream();
		Object object = stream.fromXML(ReaderFactory.newXmlReader(new File("temp.xml")));
		return object;
	}
Kategorie:Java Tagi: ,

Poszukiwanie narzedzia

17/10/2010 Dodaj komentarz

Na początku była potrzeba tworzenia dokumentacji, zostało to opisane tutaj. Miało to jednak dalszą kontynuacje.

Wraz z przejściem do projektu (trwał on już od jakiegoś czasu) stanąłem przed wyzwaniem zapoznania się z bazą danych (jedną z wielu). Dokładniej miałem do rozpoznania jej wycinek, aby przygotować kilka zapytania. I tu okazało się, że to co kiedyś stworzyłem w innym projekcie na potrzeby klienta/administratora może być teraz pomocne dla mnie. Było to sposób produkcji dokumentu przedstawiającego relacje pomiędzy tabelami w bazie. W zamierzeniu miała to być pomoc do zaznajomienia się z baza, w sam raz na początek, gdy obraz jej nie jest jeszcze utrwalony w głowie. Czytaj dalej…

Kategorie:Inne Tagi: , , ,