28 lutego 2008

Scroll Table, czyli przewijalna tabela HTML

Niniejszym inauguruję mini projekt o nazwie Scroll Table. Stroną domową projektu jest http://www.centric.pl/pl/projects/scrolltable/. Jest to rozwiązanie – a przynajmniej próba rozwiązania – problemu, o którym napisałem w artykule "Prezentacja dużych tabel na stronach HTML". Na stronie projektu umieściłem demo oraz przykładową aplikację, tak że powinno być jasne jak to działa. Póki co jest to wersja 0.1, odbiegająca jeszcze od tego co sobie wymarzyłem, aczkolwiek stabilna i w pełni funkcjonalna. Zachęcam do wykorzystania i komentarzy.

27 lutego 2008

SCJP - Modyfikatory dla deklaracji klas

Modyfikatory dla deklaracji klas, czyli streszczenie sekcji "Class Declarations and Modifiers" – kontynuacja działań zapowiedzianych w artykule "Przygotowania do SCJP czas zacząć".

Java 5 określa cztery modyfikatory, które mogą być użyte w deklaracji klasy. Dzielą się one na dwie kategorie. Pierwsza to modyfikatory widoczności, czyli w kontekście klas tylko public, alternatywnie brak modyfikatora widoczności. Druga to modyfikatory innego typu, czyli strictfp, final i abstract.

Zacznijmy od modyfikatorów widoczności. Deklarację klasy możemy ozdobić modyfikatorem public. Możemy też nie specyfikować zakresu widoczności, efektywnym będzie wówczas zakres domyślny. Modyfikator public oznacza, że klasa będzie widoczna dla każdej innej klasy. Brak modyfikatora, czyli zakres domyślny spowoduje, że klasa będzie widoczna tylko i wyłącznie dla klas zdefiniowanych w tym samym pakiecie.

Modyfikator strictfp oznacza, że wszystkie operacje zmiennoprzecinkowe w danej klasie będą zgodne ze standardem IEEE 754, tj. wirtualna maszyna Javy wykona instrukcje zmiennoprzecinkowe w sposób zgodny z tym standardem. Jak napisano w Książce, nie musimy wiedzieć co to dokładnie oznacza. Trzeba jeszcze wiedzieć, że modyfikator ten może być zastosowany tylko przy deklaracji klasy lub metody, ale nigdy przy deklaracji zmiennej. Dotyczy on w końcu operacji, także wydaje się to być dosyć oczywiste.

Została jeszcze para modyfikatorów final i abstract. Pierwszą rzeczą, z której trzeba sobie zdawać sprawę jest to, że można użyć tylko jednego z nich na raz. Klasa nie może być zadeklarowana jednocześnie final i abstract.

Zadeklarowanie klasy jako final oznacza, że nie może ona być rozszerzona, tj. nie można zadeklarować innej klasy jako podklasy klasy final. Jeśli więc klasa A jest final, to nie będzie można zadeklarować ‘class B extends A’. To tyle.

Zadeklarowanie klasy jako abstract oznacza, że nie będzie możliwe utworzenie żadnej instancji tej klasy. Do czego potrzebna jest więc taka klasa? No cóż, jest to taki "interfejs z częściową implementacją". Klasa abstrakcyjna – tj. oznaczona słówkiem kluczowym abstract – zawiera pewną liczbę (być może 0) metod abstrakcyjnych i pewną liczbę (być może 0) metod z implementacją (oraz wszelkie inne deklaracje, które może zawierać "zwykła" klasa). Metody abstrakcyjne to metody, które nie posiadają implementacji, zamiast kodu ujętego w nawiasy klamrowe umieszczamy więc na końcu deklaracji średnik – tak jak przy deklaracji metod w interfejsach. Uwaga! Klasa abstrakcyjna wcale nie musi zawierać metod abstrakcyjnych, ale jeśli któraś z metod w klasie jest abstrakcyjna, to również ta klasa musi być zadeklarowana jako abstract. Przykład klasy abstrakcyjnej poniżej.

public abstract class CollectionModifier {

public void modifyElements(Collection collection) {
for(Object obj : collection) {
this.operation(obj);
}
}

protected abstract void operation(Object obj);
}

25 lutego 2008

O Javie film obowiązkowy

Dla tych, co nie widzieli film obowiązkowy! Co prawda Przemek nie jest jego twórcą ale to właśnie na jego blogu się na niego natknąłem więc tam podaje link. O jakim filmie mówię? To trzeba zobaczyć samemu - "Java.... a to podobno taki prosty język ;-)".

22 lutego 2008

SCJP - Organizacja pliku kodu źródłowego języka Java

Organizacja pliku kodu źródłowego języka Java, czyli "Source File Declaration Rules" – kontynuacja działań zapowiedzianych w artykule "Przygotowania do SCJP czas zacząć". Temat mało ciekawy, więc będzie krótko. Oto obowiązujące zasady:

- W pliku źródłowym może być zadeklarowana tylko jedna klasa publiczna, ale klas nie publicznych może już być dowolnie wiele. Jeśli plik zawiera klasę publiczną to musi się on nazywać tak jak ta klasa i dodatkowo posiadać rozszerzenie (przyrostek) '.java'. Jeśli nie zawiera klasy publicznej to jego nazwa może być dowolna, choć zapewne również musi mieć rozszerzenie '.java' – Książka milczy na ten temat. Książka nie precyzuje też, czy te same zasady dotyczą interfejsów, ale zapewne tak.

- Jeśli klasa znajduje się w jakimś pakiecie to deklaracja pakietu (słowo kluczowe package) musi być pierwszą instrukcją w pliku.

- Jeśli klasa importuje inne klasy (słowo kluczowe import) to musi to zrobić po deklaracji pakietu a przed deklaracją klasy.

- Importy i deklaracja pakietu dotyczą wszystkich klas w pliku – wydaje się to być dosyć oczywiste, ale powtarzam dla spokoju za Książką.

SCJP - Standardy nazewnicze ziaren JavaBeans

Standardy nazewnicze ziaren JavaBeans, czyli streszczenie sekcji "JavaBeans Standards" – kontynuacja działań zapowiedzianych w artykule "Przygotowania do SCJP czas zacząć". Będzie więc o tym, co mówi specyfikacja JavaBeans w zakresie nazw identyfikatorów.

Ziarna JavaBean to klasy będące kolekcją właściwości (ang. properties). Właściwość definiujemy w ziarnie JavaBean tworząc publiczne metody set<NazwaWłaściwości> oraz get<NazwaWłaściwości>. Dla właściwości typu boolean dopuszczalna jest także metoda postaci is<NazwaWłaściwości> zamiast get<NazwaWłaściwości>, ale mogą też być obie, choć nie wiadomo jaki miałoby to mieć sens. Przykładowo, dla właściwości typu boolean o nazwie allowed będzie to setAllowed i isAllowed (albo getAllowed) a dla właściwości prop dowolnego innego typu setProp i getProp. Wystarczy przy tym, że obecna jest tylko jedna z tych metod. Mamy wtedy do czynienia z właściwością tylko do zapisu (metoda set) lub tylko do odczytu (metoda get albo is). Co prawda nie musi być tak, że każdej właściwości odpowiada zmienna prywatna ziarna ale przeważnie tak właśnie jest. W Książce nie jest to powiedziane, ale właściwości obowiązują zapewne te same reguły nazewnicze, co zmienne. To, jakie są konwencje nazewnicze dla zmiennych opisałem w artykule "SCJP - Poprawne identyfikatory i konwencje nazewnicze". Właściwości definiuje się – jak już napisałem, poprzez metody – w ten sposób, że zmieniamy pierwszą literę pożądanej nazwy właściwości na wielką i dodajemy przedrostek set, get albo is. Dodatkowo, mimo że nie dotyczy to już stricte nazewnictwa obowiązują następujące reguły:

- Metody set muszą być publiczne (modyfikator public), nie mogą zwracać żadnego rezultatu (tj. zwracać typ void) i muszą akceptować pojedynczy argument o typie właściwości.

- Metody get i is muszą być również publiczne, nie mogą akceptować żadnych argumentów i muszą zwracać typ odpowiedni dla danej właściwości.

Książka o tym nic nie mówi, ale zerknąłem do specyfikacji JavaBeans i wyczytałem tam, że jeśli nasza właściwość jest typu tablicowego (ang. array) postaci <TypElementów>[], to można dodatkowo zdefiniować metody tej postaci:

public <TypElementów> get<NazwaWłaściwości>(int i);
public void set<NazwaWłaściwości>(int i, <TypElementów> elem);

Znaczenie takich metod jest chyba oczywiste – służą do pobierania i ustawiania wartości zapisanej na podanej pozycji w tablicy.

Specyfikacja JavaBeans opisuje też zasady dotyczące klas implementujących model zdarzeń (ang. events), a konkretnie chodzi o nazwy metod służących do rejestrowania i derejestrowania klas obserwatorów (ang. listeners) w klasach generujących zdarzenia (ang. event source). Metody te powinny być tej postaci:

public void add<KlasaObserwatora>(<KlasaObserwatora> listener);
public void remove<KlasaObserwatora>(<KlasaObserwatora> listener);

Dodatkowo, klasa będąca klasą obserwatora, tj. konsumująca zdarzenia powinna mieć w nazwie słowo 'Listener' na końcu, np. MouseEventListener.

20 lutego 2008

SCJP - Poprawne identyfikatory i konwencje nazewnicze

Poprawne identyfikatory i konwencje nazewnicze, czyli "Legal Identifiers" oraz "Sun's Java Code Conventions". Tak jak zapowiedziałem w artykule "Przygotowania do SCJP czas zacząć" zaczynam serię artykułów. Dzisiejszy temat wydaje się być banalny, ale jak się okazało i w tej dziedzinie nie wszystko jest jasne i oczywiste - można się czegoś nauczyć.

Każda klasa (no, poza klasami anonimowymi), interfejs, metoda, zmienna czy stała muszą się jakoś nazywać. Właściwe nadawanie nazw ma dwa wymiary. Po pierwsze, nazwa musi być poprawna – bez tego nasz kod się po prostu nie skompiluje – po drugie, nazwa powinna być "ładna", ze względu na czytelność kodu. Poprawność nazwy (identyfikatora) określają następujące zasady:

- Musi zaczynać się od litery (alfabetem jest Unicode, więc dozwolone są litery polskie i każde inne), symbolu waluty, w praktyce ‘$’, albo znaku łączącego, czyli chyba tylko ‘_’, bo ‘-‘ już nie. Każdy kolejny znak identyfikatora może być dodatkowo cyfrą, ale pierwszy nie!

- Nie ma ograniczenia na długość nazwy.

- Identyfikatorem nie może być słowo kluczowe języka, upewnijmy się tutaj, że znamy wszystkie słowa kluczowe, w tym te rzadziej stosowane jak: continue, goto, native, strictfp, transient, volatile, enum.

- Java jest wrażliwa na wielkość liter (ang. case-sensitive), litera ‘f’ nie jest w końcu tym samym co litera ‘F’, tak więc ‘Foo’ jest czym innym niż ‘foo’. Jakby się zastanowić to jest to oczywiste, w końcu typ prymitywny boolean to co innego niż klasa Boolean. Wartością typu boolean też może być tylko true albo false, a nie np. TRUE.

Innym zagadnieniem jest "ładność" (ang. naming convention) nazwy, tj. zgodność z zaleceniami Sun’a. Jeśli chodzi o identyfikatory to można to ograniczyć do następujących zasad:

- Nazwy klas i interfejsów powinny być zlepkiem słów pisanych wielką literą (pierwsza wielka a reszta mała), czyli np. SourceManager ale nie sourceManager czy SOURCE_MANAGER. Taki styl nazewniczy określa się czasem mianem "camel case".

- Podobno, nazwy interfejsów powinny być też zazwyczaj przymiotnikami (ang. adjective), np. Serializable, ale jakoś nie specjalnie pasuje mi to do większości interfejsów typowego programu, ot weźmy takie klasy i interfejsy DAO. W każdym razie na egzamin lepiej wiedzieć jakie jest zalecenie :)

- Metody obowiązują te same zasady co klasy, z tym że pierwsza litera musi być mała a nie wielka, czyli np. getData a nie GetData. Dodatkowo, nazwy powinny być parami czasownik-rzeczownik (ang. verb-noun), np. getData czy setCustomerId. Książka przemilcza problem skrótów w stylu DAO czy ID. Z ogólnych zasad wynika, że właściwą nazwą jest właśnie setCustomerId, ale czy na pewno nie powinno być setCustomerID?

- Zmienne, tak jak metody powinny być zlepkiem słów pisanych wielką literą, z tym wyjątkiem, że pierwsza litera musi być mała. Poza tym, jak zawsze jest zalecenie, aby nazwy były znaczące i możliwie, ale nie przesadnie zwięzłe, np. firstName albo po prostu name.

- Stałe to takie "zmienne" oznaczone modyfikatorami static i final. Zalecane jest, aby identyfikator dla stałej składał się ze słów pisanych samymi wielkimi literami połączonymi znakiem ‘_’, np. MAX_THREADS.

19 lutego 2008

Przygotowania do SCJP czas zacząć

Dosyć tego dobrego. Choć ciekawych technologii i zagadnień, które chciałbym poznać jest cała masa, ze względów pragmatycznych na szczyt mojej listy TODO podbijam certyfikacje Sun Certified Java Programmer dla Java 5, czyli SCJP 5. Jeszcze nie wiem czy dotrwam do końca, ale biorę do ręki książkę "SCJP Sun Certified Programmer for Java 5 Study Guide (Exam 310-055)" i zaczynam maraton. Mój plan jest taki, że w miarę czytania, rozdział po rozdziale, dla lepszego utrwalenia materiału i późniejszej referencji będę publikował na tym blogu streszczenia z komentarzem. Na ile ten plan mi się powiedzie to się okaże. Mam nadzieje, że obietnica tych publikacji zmobilizuje mnie do sprawnego przejścia przez książkę i zdobycia certyfikatu SCJP 5.

7 lutego 2008

Publikowanie do prywatnego repozytorium Maven 2

W artykule "Artifactory, czyli prywatne repozytorium Maven 2" opisałem proces instalacji i konfiguracji prywatnego repozytorium Maven 2 – Artifactory – i pokazałem jak skonfigurować klienta Maven by pobierał z niego zależności. Pozostał jeszcze do wykonania jeden krok – publikacja modułów naszego projektu do tegoż repozytorium tak, aby mogły być pobrane jako zależności innych modułów, w końcu to o to właśnie nam chodzi. Jedną z możliwości jest powierzenie zadania budowania i publikacji modułów serwerowi budowania, np. Continuum czy LuntBuild. Wtedy architektura naszego rozwiązania wygląda jakoś tak:


Ale dziś napiszę o innym rozwiązaniu, nieco uproszczonej wersji, która może być właściwsza dla nie dużych i krótkotrwałych projektów. W wersji tej nie używamy dedykowanego serwera budowania – mowa oczywiście o serwerze w sensie oprogramowania a nie maszyny – a jego role przejmują programiści i ich IDE. Wygląda to wtedy tak:


A zatem jak skonfigurować nasz projekt Maven, aby móc publikować do zdalnego, prywatnego repozytorium? Trochę zależy to od naszego repozytorium, a konkretnie od obsługiwanego przez to repozytorium protokołu komunikacyjnego. Ten artykuł dotyczy jednak Artifactory i zakłada że jego konfiguracja jest zgodna z tą opisaną w artykule cytowanym na początku. Jedyne, co trzeba zrobić to dodać do naszego pliku pom.xml następujący fragment:

<distributionManagement>
<repository>
<id>central</id>
<url>http://<host>:<port>/artifactory/libs-releases</url>
<uniqueVersion>false</uniqueVersion>
</repository>
<snapshotRepository>
<id>central</id>
<url>http://<host>:<port>/artifactory/libs-snapshots</url>
<uniqueVersion>false</uniqueVersion>
</snapshotRepository>
</distributionManagement>

Element repository określa repozytorium przechowujące wersje dystrybucyjne (ang. releases) a element snapshotRepository repozytorium przechowujące wersje tymczasowe (ang. snapshots). W moim przypadku są to odpowiednio repozytoria o nazwach libs-releases i libs-snapshots. Poniżej przytaczam ich definicje. Jest to fragment domyślnej konfiguracji, pliku konfiguracyjnego Artifactory:

<localRepository>
<key>libs-releases</key>
<description>Local repository for in-house libraries</description>
<handleReleases>true</handleReleases>
<handleSnapshots>false</handleSnapshots>
</localRepository>
<localRepository>
<key>libs-snapshots</key>
<description>Local repository for in-house snapshots</description>
<handleReleases>false</handleReleases>
<handleSnapshots>true</handleSnapshots>
</localRepository>

Podkreślę jeszcze, że jako repozytorium nie możemy tu użyć http://<host>:<port>/artifactory/repo tak jak to zrobiłem (w innym celu) w poprzednim, cytowanym na początku artykule. Jest to bowiem repozytorium wirtualne, będące swego rodzaju widokiem na sumę repozytoriów rzeczywistych i służy z tej racji tylko do odczytu. Aby opublikować tak skonfigurowany projekt wystarczy wydać polecenie 'mvn deploy'.

3 lutego 2008

Artifactory, czyli prywatne repozytorium Maven 2

Stało się, w końcu nie wytrzymałem i wziąłem się poważnie za prace nad swoim warsztatem programistycznym. Red Hat Developer Studio zirytowało mnie już wystarczająco, przesiadłem się więc na Maven 2! Muszę powiedzieć, że póki co jestem zachwycony. Zapewne z czasem przyjdą też poważne trudności i rozczarowania, ale na razie jest super, tym bardziej, że od razu zacząłem ostro i mogę zachwycać się takimi rzeczami jak chociażby integracja poprzez repozytorium kodu z serwerem automatycznego budowania (ang. Continuous Integration Server). Szybko jednak stwierdziłem, że aby sprawnie zrealizować przy pomocy Maven 2 nie trywialny projekt niezbędna jest instalacja prywatnego repozytorium. Dzisiejszy artykuł poświęcony jest właśnie temu tematowi – repozytoriom Maven, a w szczególności instalacji i konfiguracji repozytorium Artifactory.

Mam jakieś takie zamiłowanie do opisywania tematów od podstaw, zatem zacznę od paru zdań na temat repozytoriów Maven 2. Przede wszystkim, repozytorium może być zdalne, albo lokalne. Repozytorium lokalne jest to swego rodzaju pamięć podręczna rezydująca na stacji roboczej, na której uruchamiany jest klient Maven’a. Jest to po prostu struktura katalogów na naszym komputerze przechowująca biblioteki pobrane z repozytoriów zdalnych. Repozytoria zdalne dzielą się, ogólnie rzecz biorąc, na repozytoria publiczne i prywatne. Repozytoria publiczne to te udostępnione w Internecie i umożliwiające pobieranie zależności bez konieczności uwierzytelnienia się, po prostu dla każdego. Repozytorium prywatne różni się od publicznego tym, że jest dedykowane dla pewnej organizacji lub projektu a dostęp do niego jest chroniony.

Wyobraźmy sobie, że tworzymy projekt Maven 2 składający się z wielu modułów powiązanych wzajemnymi zależnościami. Jeśli moduł A potrzebuje jako zależności modułu B to deklarujemy to w pliku pom.xml modułu A i to powinno wystarczyć. W rzeczy samej, wystarczy, ale tylko pod warunkiem, że mamy do dyspozycji repozytorium prywatne, które przechowuje i udostępnia moduły tego projektu. No chyba, że jesteśmy jedynym programistą zaangażowanym w projekcie i wystarczy nam współdzielenie poprzez repozytorium lokalne, ale jest to przypadek skrajny i nieinteresujący.

Zaczynamy od pobrania Artifactory. W chwili pisania tego artykułu najnowszą wersją jest 1.2.5 i to właśnie tej wersji użyłem dla swojej instalacji. Artifactory to aplikacja WWW, którą uruchamiamy w kontenerze serwletów (ang. servlet container). Dokumentacja Artifactory mówi o dwóch opcjach instalacji: jedną jest uruchomienie na wbudowanym kontenerze Jetty a inną na dowolnym serwerze zewnętrznym implementującym odpowiednie standardy, np. na serwerze Tomcat. Ja wybrałem instalację na serwerze Tomcat 6.0.14. Sama instalacja jest procesem trywialnym, oczywiście o ile nie natrafi się na poza standardowe trudności. Ja nie natrafiłem i w zasadzie nie mam nic do dodania względem tego, co jest w dokumentacji Artifactory. Pobrane archiwum .zip rozpakowujemy w dowolnej lokalizacji, kopiujemy plik /webapps/artifactory.war do podkatalogu webapps katalogu domowego serwera Tomcat i ustawiamy zmienną artifactory.home tak aby wskazywała na katalog domowy instalacji Artifactory. To ostatnie możemy zrealizować na wiele sposobów, jednym z nich jest przypisanie zmiennej środowiskowej JAVA_OPTS lub CATALINA_OPTS wartości '-Dartifactory.home=<katalog główny Artifactory>'. To tyle, przechodzimy do konfiguracji. W tym celu edytujemy plik konfiguracyjny Artifactory /etc/artifactory.config.xml. Tutaj definiujemy repozytoria, proces tworzenia automatycznych kopii bezpieczeństwa, konfigurujemy proxy oraz co w tej chwili najważniejsze, tutaj deklarujemy, że nasze repozytorium jest rzeczywiście prywatne. Prywatne w tym sensie, że nie jest możliwy anonimowy, nie autoryzowany dostęp. Plik ten zawiera pewną domyślną konfigurację i nie musimy zmieniać zupełnie nic żeby aplikacja po prostu działała, ale powinniśmy wykonać ten jeden mały krok polegający na od komentowaniu (albo dodaniu, jeśli go niema) elementu:

<anonDownloadsAllowed>false</anonDownloadsAllowed>

Spowoduje to jak można się domyślić, że nie będzie możliwy anonimowy, nie autoryzowany dostęp do naszych zasobów. Warte odnotowania jest jeszcze to, że Artifactory dzieli repozytoria na lokalne (element localRepositories) i zdalne (element remoteRepositories). Repozytoria zdalne to częściowe kopie repozytoriów publicznych, punkt pośredni dla pobierania bibliotek a repozytoria lokalne to te, których Artifactory jest – nazwijmy to – właścicielem i administratorem. To by było na tyle jeśli chodzi o wstępną konfigurację, możemy uruchomić serwer i obejrzeć konsolę administracyjną. Uruchamiamy więc przeglądarkę, nawigujemy pod adres http://localhost:8080/artifactory i logujemy się używając identyfikatora 'admin' oraz domyślnego hasła 'password'. Musimy teraz utworzyć jakiegoś użytkownika na potrzeby klienta Maven i nadać mu uprawnienia do odczytu (rola Reader) oraz, co ważne, również do zapisu (rola Deployer) do repozytoriów. Później wyjaśnię, dlaczego. Poniżej prezentuje mój ekran konfiguracji dostępu.




Pozostała jeszcze konfiguracja klienta Maven 2. Po pierwsze, musimy Maven’owi dostarczyć identyfikator i hasło użytkownika Artifactory. W tym celu edytujemy plik konfiguracyjny /.m2/settings.xml. Dodajemy tu następujący fragment:

<servers>
<server>
<id>central</id>
<username>maven</username>
<password>passwd</password>
</server>
</servers>

Komentarza wymaga wartość elementu id. Jest to identyfikator serwera, do którego będziemy się następnie odwoływać w pliku pom.xml i może to być dowolna nazwa z tym, że akurat 'central' jest wartością specjalną, ale o tym za chwile. Edytujmy teraz plik pom.xml naszego projektu i umieśćmy tam następujący fragment:

<repositories>
<repository>
<id>central</id>
<url>http://localhost:8080/artifactory/repo</url>
</repository>
</repositories>

Ważne jest, aby element id miał tę samą wartość, co element id, dla serwera zdefiniowanego przed chwilą w pliku /.m2/settings.xml. Dodatkowo, jeśli wartość ta to 'central' to repozytorium to zasłoni repozytorium główne Maven’a. Co to oznacza? Oznacza to tyle, że wszelkie zależności Maven będzie rozwiązywał z użyciem naszego repozytorium Artifactory, które z kolei nie mogąc znaleźć odpowiednich zasobów w swoich repozytoriach lokalnych będzie ich wyszukiwało korzystając ze zdefiniowanych repozytoriów zdalnych. W takim wypadku Artifactory pobierze wpierw zależność z repozytorium zdalnego, doda ją do swojego repozytorium lokalnego i dopiero zwróci do klienta Maven inicjalizującego operację. W tym momencie powinno już być jasne, dlaczego użytkownik Artifactory wykorzystywany przez klienta Maven powinien mieć prawo do zapisu do repozytoriów. Gdyby tego prawa nie miał, nie było by możliwe pobieranie za pośrednictwem Artifactory zasobów z repozytoriów publicznych, nie było by bowiem możliwe umieszczenie artefaktu w repozytorium pośredniczącym. Pozostaje jeszcze wykonać test. W tym celu zdefiniujmy zakąś zależność od biblioteki dostępnej w repozytorium publicznym a nie obecnej jeszcze w naszym repozytorium lokalnym i uruchommy Maven’a. Jeśli wszystko jest dobrze biblioteka powinna być – oprócz tego, że pobrana – widoczna w drzewie repozytoriów Artifactory. Oto przykładowy widok: