2008.11_Spring 2 Schema _[Projektowanie XML].pdf

(505 KB) Pobierz
441732201 UNPDF
XML
Spring 2 Schema
Własne przestrzenie nazw w Spring 2.x
Ten artykuł wprowadzi Cię szybko w podstawowe techniki tworzenia
własnych przestrzeni nazw XML Schema dla plików konfiguracyjnych
Spring IOC. Autorzy Spring Framework pisząc o dobrym oprogramowaniu
promują zasadę DRY (Don't Repeat Yourself) – wyraźnie widać to w
mechanizmie rozszerzania konfiguracji XML kontenera Springa.
Dowiesz się:
• Jak za pomocą własnej przestrzeni nazw XML
stworzyć najprostsze rozszerzenia składni pli-
ków koniguracyjnych XML dla Spring Frame-
work w wersji 2.x.
Powinieneś wiedzieć:
• Podstawowa znajomość języka Java oraz kon-
iguracja kontenera Inversion Of Control dla
Spring Framework 2.x za pomocą plików XML;
• Wskazana jest również minimalna wiedza z za-
kresu języka XML oraz API programowej ob-
sługi kontenera Spring IOC.
rzyć. Zaliczyć do nich należy głównie usprawnio-
ne uzupełnianie składni w edytorach XML do-
stępnych w popularnych IDE oraz zestaw dodat-
kowych przestrzeni nazw włączonych do dystry-
bucji Springa począwszy do wersji 2.0. W szcze-
gólności predefiniowane przestrzenie nazw oka-
zują się być przydatne w codziennej pracy – po-
zwalają one m.in. na zastąpienie rozbudowanych
definicji fabryk typu FieldRetrievingFactoryBean,
ListFactoryBean lub TransactionProxyFactoryBe-
an ich kompaktowymi odpowiednikami wyrażo-
nymi za pomocą określonej przestrzeni nazw.
Twórcy Springa nie poprzestali na szczęście
na dostarczeniu nam zestawu predefiniowa-
nych przestrzeni nazw, ale udostępnili również
mechanizm do samodzielnego tworzenia tych-
że. Nie muszę chyba wspominać o tym jak bar-
dzo konfiguracja naszej aplikacji zyska na czy-
telności po zastosowaniu elementów oraz atry-
butów własnej konstrukcji, dostosowanych do
Poziom trudności
w dalszym ciągu działają w wersji 2.0 Springa (ze
względu na słynne umiłowanie kompatybilności
wstecz przez jego autorów), jakkolwiek zalecaną
formą konfiguracji XML jest teraz XML Schema.
( Inversion Of Control ) dla języka Java. Ofe-
ruje on kilka sposobów konfiguracji apli-
kacji oraz wstrzykiwania zależności, jednak naj-
bardziej popularną techniką uzyskiwania tych ce-
lów jest konfiguracja w pliku XML. Jak powszech-
nie wiadomo XML oferuje czytelną, hierarchiczną
strukturą prezentowanych przez siebie informa-
cji, które to m.in. zapewniły mu rolę niepisanego
standardu konfiguracji aplikacji webowych. XML
jednakże cechuje się również tendencją do gadatli-
wości tzn. do konieczności opisywania zawartych
w nim danych za pomocą dużej ilości tekstu. Pro-
gramiści używający Springa w wersji niższej niż
2.0 skazani byli na używanie dość ograniczonego
zestawu narzędzi redukujących rozmiar plików
konfiguracyjnych XML oraz zjawiska tzw. XML
hell (np. stosowanie dziedziczenia definicji be-
anów lub automatycznego wiązania). Na szczęście
twórcy Springa od wersji 2.0 swojego frameworka
dodali możliwość konfiguracji aplikacji za pomocą
plików XML zdefiniowanych nie tylko zgodnie z
DTD, ale i mechanizmem XML Schema. Oczywi-
ście stare konfiguracje napisane pod kątem DTD
Motywacja
Nie trzeba nawet specjalnie zachęcać do stoso-
wania nowej definicji plików konfiguracyjnych
XML, gdyż oferuje nam ona rozliczne korzyści
o których użytkownicy DTD mogą tylko poma-
Listing 1. Szkielet koniguracji kontenera Springa oparty na XML DTD
<!-- Stara koniguracja -->
< ?xml version= "1.0" encoding= "UTF-8" ? >
< !DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd" >
< beans >
< /beans >
Listing 2. Szkielet koniguracji kontenera Springa oparty na XML Schema
<!-- Nowa koniguracja -->
< ?xml version= "1.0" encoding= "UTF-8" ? >
< beans xmlns= "http://www.springframework.org/schema/beans"
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-2.0.xsd" >
< /beans >
52
11/2008
S pring jest popularnym frameworkiem IOC
441732201.037.png 441732201.038.png 441732201.039.png 441732201.040.png 441732201.001.png 441732201.002.png 441732201.003.png 441732201.004.png 441732201.005.png 441732201.006.png 441732201.007.png
Spring 2 Schema
naszych konkretnych potrzeb. Zysk ten będzie
widoczny w szczególności jeżeli planujemy
wielokrotne wykorzystywanie naszego kodu w
aplikacjach używających np. pisanej przez nas
biblioteki. W artykule tym chciałbym właśnie
przedstawić podstawowe techniki rozszerzania
możliwości konfiguracyjnych XML w Springu.
Listing 3. Przykład użycia komponentu z własnej przestrzeni nazw
< ?xml version= "1.0" encoding= "UTF-8" ? >
< beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xmlns:myns= "http://www.foo.com/customSchema"
xsi:schemaLocation= "
http://www.springframework.org/schema/beans http://www.springframework.org/schema/
beans/spring-beans-2.0.xsd
http://www.foo.com/customSchema http://www.foo.com/customSchema.xsd" >
Migracja
na nowy styl konfiguracji
Przejście na nowy styl konfiguracji jest bardzo
proste. Wystarczy zamienić w istniejących pli-
kach konfiguracyjnych parę pierwszych linijek
dokumentu.
Migracja zaprezentowana na Listingu 2 jest
niemalże bezbolesna. Niemalże, gdyż istnieje
parę (dosłownie parę) szczegółów konfigura-
cji które zostały uznane przez twórców Sprin-
ga za przestarzałe (deprecated) i które należy w
związku z tym dostosować do nowej konfigura-
cji opartej na XML Schema. Do szczegółów te-
go typu należy np. atrybut singleton elemen-
tu <bean> , który w nowej konfiguracji powi-
nien zostać zamieniony na atrybut scope (ze
względu na wprowadzenie mechanizmu roz-
szerzalnych zasięgów w nowszych wersjach
Springa).
< myns:bar id= "bar" value= "barValue" / >
< /beans >
Listing 4. Kod przykładowego komponentu Bar
package foo;
public class Bar {
// wartość komponentu
private String value;
public Bar(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
Witaj przestrzenio
– przypadek użycia
Na początku spróbujemy napisać jak najszyb-
ciej najprostszą przestrzeń nazw z jednym ele-
mentem. Na potrzeby przykładów minimal-
nych zawartych w tym artykule załóżmy, że
pracujemy dla firmy Foo i naszym zadaniem
jest stworzenie elementu XML który pozwo-
li nam na bardziej efektywne używanie kom-
ponentu Bar w aplikacjach korzystających ze
sprzedawanej przez nas biblioteki. Wyobraźmy
sobie, że docelowo nasz klient chciałby konfi-
gurować swoją aplikację za pomocą komponen-
tu Bar w następujący sposób – Listing 3.
Oczekujemy, że powyższa konfiguracja utwo-
rzy w kontenerze instancję klasy Bar o id rów-
nym bar oraz wartości prywatnej właściwości
value równej barValue . Sam komponent Bar
wygląda następująco – Listing 4.
Listing 5. Dokument XML Schema deiniujący przykładową przestrzeń
< ?xml version= "1.0" encoding= "UTF-8" ? >
< xsd:schema xmlns= "http://www.foo.com/customSchema"
xmlns:xsd= "http://www.w3.org/2001/XMLSchema"
xmlns:beans= "http://www.springframework.org/schema/beans"
targetNamespace= "http://www.foo.com/customSchema"
elementFormDefault= "qualiied"
attributeFormDefault= "unqualiied" >
< xsd:import namespace= "http://www.springframework.org/schema/beans" / >
< xsd:element name= "bar" >
< xsd:complexType >
< xsd:complexContent >
< xsd:extension base= "beans:identiiedType" >
< xsd:attribute name= "value" type= "xsd:string" use= "required" / >
< /xsd:extension >
< /xsd:complexContent >
< /xsd:complexType >
< /xsd:element >
< /xsd:schema >
Schemat kroków
Klasyczny schemat kroków wykonywany podczas
tworzenia własnej przestrzeni nazw to kolejno:
• napisanie dokumentu XSD;
• stworzenie parserów dla nowych elemen-
tów lub atrybutów XML;
• zaprogramowanie własnej klasy typu
NamespaceHandler , która pozwoli nam na
zmapowanie parserów i dekoratorów do
określonych elementów i atrybutów XML;
• dodanie do wynikowej aplikacji lub biblio-
teki meta-danych potrzebnych Springowi.
W Sieci
http://springframework.org – Strona projektu Spring Framework
http://static.springframework.org/spring/docs/2.5.x/api – Spring 2.5 API
http://static.springframework.org/spring/docs/2.5.x/reference/xsd-conig.html – Koniguracja
oparta na XML Schema w Spring 2.5
http://static.springframework.org/spring/docs/2.5.x/reference/extensible-xml.html – Własna prze-
strzeń nazw wg Spring 2.5 Reference
http://www.w3.org/XML/Schema – XML Schema
http://www.w3.org/ – DOM XMl DOM
W kolejnych sekcjach opiszę szerzej każdy z
tych kroków.
www.sdjournal.org
53
441732201.008.png 441732201.009.png 441732201.010.png 441732201.011.png 441732201.012.png 441732201.013.png 441732201.014.png 441732201.015.png 441732201.016.png 441732201.017.png 441732201.018.png
XML
Dokument XSD
Dokument XML Schema pozwoli nam określić
składnię naszej przestrzeni nazw, czyli m.in. ja-
kie elementy oraz atrybuty są w niej dopusz-
czalne, a jakie nie. Schema uwzględnia również
informacje o tym jakie typy danych zawarte są
w poszczególnych elementach i atrybutach na-
szej przestrzeni oraz czy są one obowiązkowe.
Interesujący nas schemat mógłby mieć następu-
jącą postać – Listing 5.
Tematyka tworzenia definicji XML Schema
jest poza zakresem tego artykułu. Ograniczę się
zatem do podsumowania, że zdefiniowaliśmy
właśnie element o nazwie bar zawierający jeden
(wymagany) atrybut o nazwie value . Element
ten dziedziczy również po identyfikowalnym
typie Springa, co w praktyce oznaczna tyle, że
również implicite dziedziczy atrybut id . Na-
stępnym krokiem zbliżającym nas do działającej
przestrzeni nazw będzie zmapowanie elementu
XML zdefiniowanego powyżej do Javy.
Listing 6. Przykładowy parser komponentu Bar
package foo;
import org.springframework.beans.factory.support.BeanDeinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDeinitionParser;
import org.w3c.dom.Element;
public class BarParser extends AbstractSingleBeanDeinitionParser {
@Override
// Oczekujemy instancji klasy Bar
protected Class < Bar > getBeanClass(Element element) {
return Bar.class;
}
@Override
protected void doParse(Element element, BeanDeinitionBuilder builder) {
// Odczytaj wartość atrybutu
String value = element.getAttribute("value");
// i dodaj ją jako argument konstruktora wynikowej instancji
builder.addConstructorArgValue(value);
}
}
Parser elementu
Aby przekonwertować element XML do instan-
cji zarejestrowanej w kontenerze musimy napi-
sać parser implementujący interfejs org.spring
framework.beans.factory.xml.BeanDefiniti
onParser . Klasy implementujące wspomniane-
go interfejsu służą do analizy pojedynczego ele-
mentu XML znajdującego się bezpośrednio mię-
dzy elementami <beans></beans> , wraz z ew.
podelementami znajdującymi się wewnątrz na-
szej definicji. Nasz konkretny element <bar> jest
raczej prosty tzn. nie zawiera zagnieżdżonych
elementów i zwróci tylko jedną instancję (klasy
Bar ) do rejestracji w kontrolerze. Ograniczmy się
zatem do dziedziczenia z klasy AbstractSingle
BeanDefinitionParser – Listing 6.
Klasa BeanDefinitionBuilder jest jedną z
najważniejszych klas programowej obsługi kon-
tenera Springa.
Temat ten zasługuje na co najmniej parę
osobnych artykułów, tak więc ograniczę się tyl-
ko do podania informacji, że klasa ta służy do
programowego tworzenia instancji klasy prze-
znaczonej do rejestracji w kontenerze. W tym
konkretnym przykładzie chcemy, aby nowy
obiekt klasy Bar został stworzony za pomocą
jednoargumentowego konstruktora.
Listing 7. Handler mapujący przykładowy element 'bar' do wybranego parsera
package foo;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class BarNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// zarejestruj instancję parsera dla
// elementów <bar/> z tej przestrzeni nazw
registerBeanDeinitionParser("bar", new BarParser());
}
}
Listing 8. Zawartość pliku META-INF/spring.handlers
http\://www.foo.com/customSchema=foo.BarNamespaceHandler
Listing 9. Zawartość pliku META-INF/spring.schema
http\://www.foo.com/customSchema.xsd=foo/foo.xsd
Listing 10. Kod minimalnego komponentu 'Bar' rozszerzonego o listę swoich potomków
package foo;
import java.util.List;
public class Bar {
private String value;
private List < Bar > children;
public Bar(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
public void setChildren(List < Bar > children) {
this.children = children;
}
public List < Bar > getChildren() {
return children;
}
}
Zarejestrowanie
elementu w NamespaceHandler
Instancje interfejsu org.springframework.bean
s.factory.xml.NamespaceHandler służą do łą-
czenia przestrzeni nazw z parserami elementów
oraz atrybutów XML. Sam NamespaceHandler
nie wykonuje logiki związanej z analizą elemen-
tów i atrybutów XML, ponieważ całą logikę
związaną z czytaniem dokumentu XML zawar-
liśmy w poprzednim kroku (w definicji parse-
ra). NamespaceHandler oferuje parę metod po-
zwalających na interakcję z nim w określonych
momentach jego cyklu życia, jakkolwiek na na-
sze skromne potrzeby zainteresujemy się jedynie
bezargumentową metodą init() wywoływaną
w momencie inicjalizacji handlera.
W powyższym przykładzie (Listing 7) zma-
powaliśmy parser napisany w poprzednim
kroku do elementu XML <bar> . W miażdżą-
cej większości przypadków jeden handler bę-
54
11/2008
441732201.019.png 441732201.020.png 441732201.021.png 441732201.022.png 441732201.023.png 441732201.024.png 441732201.025.png
 
Spring 2 Schema
dzie mapował wiele parserów i/lub dekorato-
rów –nie implementujemy wielu handlerów
dla jednej przestrzeni nazw. Jak wspomnia-
łem wcześniej nasze potrzeby względem han-
dlera są bardzo skromne – dlatego właśnie
dziedziczymy z klasy org.springframework.
beans.factory.xml.NamespaceHandlerSupp
ort . Dzięki wspomnianej klasie pomocniczej
możemy nadpisać metodę init() interfejsu
oraz nie martwić się o logikę związaną z reje-
stracją parsera.
Listing 11. Przykład użycia zagnieżdżonego komponentu
< myns:bar id= "bar" value= "parent" >
< myns:bar value= "child1" >
< myns:bar value= "grandChild" / >
< /myns:bar >
< myns:bar value= "child2" / >
< /myns:bar >
Listing 12. Uaktualniony dokument XML Schema uwzględniający zagnieżdżanie elementów
< ?xml version= "1.0" encoding= "UTF-8" ? >
< xsd:schema xmlns= "http://www.foo.com/customSchema"
xmlns:xsd= "http://www.w3.org/2001/XMLSchema"
targetNamespace= "http://www.foo.com/customSchema"
elementFormDefault= "qualiied" attributeFormDefault= "unqualiied" >
Meta-dane dla Springa
Ostatnim krokiem jest dodanie do korzenia
ścieżki klas naszej aplikacji lub biblioteki fol-
deru META-INF wraz z plikami spring.handlers
oraz spring.schemas – Listing 8 i Listing 9.
Jak widać pierwszy z nich mapuje URI prze-
strzeni nazw na napisany przez nas wcześniej
handler – tą metodą Spring wie których par-
serów powinien użyć dla poszczególnych ele-
mentów i atrybutów w określonej przestrzeni
nazw. Drugi zaś wskazuje fizyczną lokalizację
pliku XSD z definicją naszej przestrzeni – w
tym konkretnym przypadku plik z definicją po-
winien znajdować się w pakiecie foo i nazywać
się foo.xsd . Pragę zwrócić uwagę na koniecz-
ność poprzedzania znaków dwukropka w oby-
dwu plikach znakiem backslash (ze względu na
fakt, że nie tylko znak równości, ale i dwukro-
pek są poprawnymi symbolami końca klucza w
plikach właściwości Javy).
< xsd:element name= "bar" >
< xsd:complexType >
< xsd:choice minOccurs= "0" maxOccurs= "unbounded" >
< xsd:element ref= "bar" / >
< /xsd:choice >
< xsd:attribute name= "id" type= "xsd:ID" / >
< xsd:attribute name= "value" use= "required" type= "xsd:string" / >
< /xsd:complexType >
< /xsd:element >
< /xsd:schema >
Listing 13. Parser elementu 'bar' uwzględniający rekurencję
package foo;
import java.util.List;
import org.springframework.beans.factory.support.AbstractBeanDeinition;
import org.springframework.beans.factory.support.BeanDeinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.AbstractBeanDeinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
public class BarParser extends AbstractBeanDeinitionParser {
Zagnieżdżanie elementów
– rozszerzony przypadek użycia
Powyższy przykład jest nieco prosty, gdyż za-
kłada że sparsowany element XMLa zareje-
struje tylko jedną instancję określonej klasy w
kontrolerze. Jeżeli chcielibyśmy rekurencyjnie
parsować i rejestrować zagnieżdżone elemen-
ty XML powinniśmy stworzyć parser dziedzi-
czący po czymś potężniejszym niż AbstractSi
ngleBeanDefinitionParser – tą klasą jest np.
AbstractBeanDefinitionParser . Wyobraź-
my sobie, że nasz przypadek użycia rozszerzy-
my w następujący sposób – otóż nasz potężny
komponent Bar został rozszerzony o listę swo-
ich dzieci (dla uproszczenia przykładu również
instancji klasy Bar ) – Listing 10.
Przykładowy scenariusz konfiguracji drzewa
komponentów Bar w pliku XML mógłby wy-
glądać następująco – Listing 11.
Powyższa zmiana konfiguracji pociąga za so-
bą oczywiście konieczność aktualizacji doku-
mentu XML Schema – Listing 12.
Poza schematem XML w stosunku do po-
przedniego przykładu zmianie uległby w zasa-
dzie tylko sam parser – Listing 13.
Powyższy parser mógłby dziedziczyć po kla-
sie AbstractSingleBeanDefinitionParser i
dalej zwracać wynik zgodny z zadanym scena-
riuszem, jakkolwiek dziedziczenie po Abstrac
tBeanDefinitionParser pozwala na jego nie-
co czytelniejszą implementację.
protected AbstractBeanDeinition parseInternal(Element element,
ParserContext parserContext) {
// Stwórz budowniczego deinicji elementu
BeanDeinitionBuilder barBuilder = BeanDeinitionBuilder
.rootBeanDeinition(Bar.class);
barBuilder.addConstructorArgValue(element.getAttribute("value"));
// Wyszukanie dzieci elementu określonego typu
List < Element > childElements = DomUtils.getChildElementsByTagName(
element, "bar");
if (childElements != null) {
// Dodanie potomków do listy zarządzanej przez kontener
ManagedList children = new ManagedList(childElements.size());
for (Element e : childElements) {
// Rekurencja
children.add(parseInternal(e, parserContext));
}
barBuilder.addPropertyValue("children", children);
}
return barBuilder.getBeanDeinition();
}
}
www.sdjournal.org
55
441732201.026.png 441732201.027.png 441732201.028.png 441732201.029.png 441732201.030.png 441732201.031.png 441732201.032.png 441732201.033.png 441732201.034.png 441732201.035.png
XML
Własne atrybuty
– przypadek użycia
Ostatnim istotnym przypadkiem użycia jest
dodanie własnego atrybutu do dowolnego ele-
mentu w pliku konfiguracyjnym – Listing 14.
Załóżmy, że chcemy aby podczas parsowania
elementu oznaczonego atrybutem myns:bar
(o dowolnej wartości) na konsoli pojawiała się
wartość licznika wskazującego ile elementów
oznaczonych identyczną wartością znaleziono
dotychczas w kontenerze.
Listing 14. Przykład użycia atrybutu XML z własnej przestrzeni nazw
< bean class= "java.lang.String" myns:bar= "barValue" >
< constructor-arg value= "someValue" / >
< /bean >
Zmiany w implementacji
Jak łatwo się domyśleć na pierwszy ogień pój-
dzie aktualizacja schematu XML – Listing 15.
Podobnie jak w przypadku własnych ele-
mentów, dla nowego atrybutu również musi-
my napisać własny parser. Możemy to wygod-
nie zrobić poprzez implementację interfejsu
BeanDefinitionDecorator – Listing 16.
Tym razem będziemy również musieli zmo-
dyfikować BarNamespaceHandler .
Wynika to z faktu, iż tym razem nie rejestru-
jemy parsera definicji beana , a tylko tzw. deko-
rator, czyli mniejszy parser służący do mody-
fikacji lub wzbogacania wybranego fragmen-
tu definicji. Oczywiście wyświetlanie informa-
cji o tym którą z kolei definicję oznaczoną kon-
kretną wartością parsuje kontener, jest w real-
nym świecie średnio przydatne, jakkolwiek do-
stęp do parametrów BeanDefinitionHolder
oraz ParserContext daje nam możliwość ma-
nipulacji kolejno definicją dekorowanego ele-
mentu (możemy również zwrócić całkowicie
nową instancję zamiast modyfikować istnie-
jącą) oraz całym rejestrem kontenera. Nieste-
ty ze względu na ograniczony rozmiar niniej-
szego artykułu jestem zmuszony przemilczeć
szczegóły dotyczące możliwości programowej
manipulacji definicjami beanów oraz zawarto-
ścią kontenera.
Listing 15. Dokument XML Schema dla minimalnego atrybutu
< ?xml version= "1.0" encoding= "UTF-8" ? >
< xsd:schema xmlns= "http://www.foo.com/customSchema"
xmlns:xsd= "http://www.w3.org/2001/XMLSchema"
targetNamespace= "http://www.foo.com/customSchema"
elementFormDefault= "qualiied" attributeFormDefault= "unqualiied" >
< xsd:attribute name= "bar" type= "xsd:string" / >
< /xsd:schema >
Listing 16. Parser minimalnego atrybutu z własnej przestrzeni
package foo;
import java.util.HashMap;
import org.springframework.beans.factory.conig.BeanDeinitionHolder;
import org.springframework.beans.factory.xml.BeanDeinitionDecorator;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Attr;
import org.w3c.dom.Node;
public class BarParser implements BeanDeinitionDecorator {
HashMap < String, Integer > counters = new HashMap < String, Integer > ();
@Override
public BeanDeinitionHolder decorate(Node node,
BeanDeinitionHolder holder, ParserContext ctx) {
// odczytaj wartość atrybutu
String value = ((Attr) node).getValue();
// sprawdź wartość licznika
Integer i = counters.get(value);
if (i == null) {
i = 0;
}
// zwiększ licznik
counters.put(value, ++i);
// wyświetl wynik
System.out.println(value + ": " + i);
return holder;
}
}
Podsumowanie
W niniejszym artykule poznaliśmy podsta-
wowe sposoby rozszerzania możliwości kon-
figuracyjnych plików XML w Springu za po-
mocą własnych przestrzeni nazw. Znając spo-
soby na analizę elementów XML najwyższe-
go poziomu (wraz z ich ew. zagniżdżenia-
mi) oraz atrybutów XML możemy rozpocząć
tworzenie własnych przestrzeni nazw, któ-
re przy minimalnej znajomości XML DOM
oraz API programowej manipulacji zawar-
tością kontenera IOC Springa pozwolą nam
na napisanie w pełni funkcjonalnych mapo-
wań dla naszych komponentów. Tematyka
tego artykułu powinna w szczególności za-
interesować osoby dostarczające dla innych
firm programistycznych gotowe rozwiąza-
nia oparte na Springu ze względu na zmini-
malizowanie wiedzy wymaganej przez klien-
ta do poprawnego stosowania naszych kom-
ponentów.
Listing 17. Handler mapujący parser do atrybutu 'bar'
package foo;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class BarNamespaceHandler extends NamespaceHandlerSupport {
HENRYK KONSEK
Autor pracuje na stanowisku projektanta JEE w
warszawskiej irmie Artegence. Udziela się rów-
nież jako administrator serwisu javablackbelt.com.
W wolnym czasie interesuje się swoją Anią oraz
m.in. psychiatrią oraz dobrymi technologiami.
Kontakt z autorem: http://www.hekonsek.pl lub he-
konsek@gmail.com.
@Override
public void init() {
registerBeanDeinitionDecoratorForAttribute("bar", new BarParser());
}
}
56
11/2008
441732201.036.png
 
Zgłoś jeśli naruszono regulamin