Tworzenie aplikacji desktopowej z Java Desktop Application w NetBeans IDE 6.1
Z Jacek Laskowski - Wiki Projektanta Java EE
Zadanie na dzisiaj - utworzyć aplikację Przychodnia, której wymagania są następujące:
- Aplikacja desktopowa z graficznym interfejsem w Swingu
- Umożliwia zarządzanie danymi swoich pacjentów (PESEL, nazwisko i imię, adres, telefon [wiek i płeć powinny się wyliczać na podstawie PESELu])
- Umożliwia zarządzanie informacjami o wizytach poszczególnych pacjentów (data, opis objawów, opis rozpoznania choroby, opis zaleconego leczenia)
- Dane zapisywane są w bazie danych i/lub plikach
Czas wykonania: 1h
Czasu nie jest wiele, więc koniecznie muszę znaleźć narzędzie, które uprości mi stworzenie aplikacji znosząc ze mnie wszelkie zawiłości technologiczne do niezbędnego minimum. Wydaje się, że NetBeans IDE 6.1 i jego typ projektu Java Desktop Application powinny się w zupełności nadać.
Dla ustalenia uwagi nie tylko czas jest ograniczeniem, ale również i moje niedociągnięcia technologiczne z zakresu SQL i tworzenia struktur bazodanowych. Zamiast bawić się w tworzenie skryptów SQL postanowiłem sprowadzić temat do utworzenia modelu aplikacji, który oparty o Java Persistence API (JPA) utworzy mi niezbędne struktury bazodanowe. Wydaje się być bardziej skomplikowane dla osób znających SQL, a niekoniecznie JPA czy NetBeans, ale jeśli dodam, że tworzenie encji to kilka kliknięć w NetBeans IDE 6.1, to sprawa powinna być jasna - podejście oparte o JPA obsłuży mi dwie sprawy - będę miał model aplikacji oraz odpowiadające mu struktury bazodanowe. Takie aplikacyjne dwa w jednym.
Spis treści |
Krok 1: Utworzenie modelu - projekt przychodnia-model
Architektura aplikacji zakłada wykorzystanie relacyjnej bazy danych. Nie znam SQL na tyle, aby próbować pisać skrypty SQL ręcznie, więc skorzystam z JPA do interakcji z bazą danych, która weźmie na siebie obowiązek utworzenia struktur bazodanowych na żądanie (podczas uruchomienia aplikacji).
Tworzę projekt Java Class Library w NetBeans IDE o nazwie przychodnia-model - Ctrl+Shitf+N i wybieram Java > Java Class Library.
Wyróżniłem 2 byty w aplikacji - Pacjent oraz Wizyta - w relacji jeden-do-wielu. Nie chcę wyłącznie korzystać z klas modelu jako bytów JPA, więc dodatkowo nakładam na siebie obowiązek trzymania konfiguracji JPA zdala od klas, które będą encjami. Klasy w pakiecie pl.jaceklaskowski.kartoteka.model będą zwykłymi POJO, czyli klasami z metodami zapisu (ang. setters) i odczytu (ang. getters).
Klasa pl.jaceklaskowski.przychodnia.model.Pacjent
Najpierw utworzę klasę pl.jaceklaskowski.przychodnia.model.Pacjent, która modeluje byt pacjenta w aplikacji.
Utworzenie klasy w NetBeans 6.1 to Ctrl+N, Java > Java Class, podanie danych klasy i Finish. Następnie w ramach klasy Alt+Insert i wybieramy menu Add Property..., gdzie definiujemy atrybuty klasy jak pesel, imie, nazwisko, itp.
package pl.jaceklaskowski.przychodnia.model;
import java.io.Serializable;
import java.util.List;
public class Pacjent implements Serializable {
private static final long serialVersionUID = 1L;
private String pesel;
private String imie;
private String nazwisko;
private String telefon;
private int wiek;
// TODO: Zmienic na Enum
private boolean plec;
private List<Wizyta> wizyty;
public Pacjent() {
}
public Pacjent(String pesel, String imie, String nazwisko, String telefon) {
this.pesel = pesel;
this.imie = imie;
this.nazwisko = nazwisko;
this.telefon = telefon;
}
public List<Wizyta> getWizyty() {
return wizyty;
}
public void setWizyty(List<Wizyta> wizyty) {
this.wizyty = wizyty;
}
public void setPesel(String pesel) {
this.pesel = pesel;
}
public String getPesel() {
return pesel;
}
public String getImie() {
return imie;
}
public void setImie(String imie) {
this.imie = imie;
}
public String getNazwisko() {
return nazwisko;
}
public void setNazwisko(String nazwisko) {
this.nazwisko = nazwisko;
}
public boolean isPlec() {
return plec;
}
public void setPlec(boolean plec) {
this.plec = plec;
}
public String getTelefon() {
return telefon;
}
public void setTelefon(String telefon) {
this.telefon = telefon;
}
public int getWiek() {
return wiek;
}
public void setWiek(int wiek) {
this.wiek = wiek;
}
@Override
public int hashCode() {
int hash = 0;
hash += (pesel != null ? pesel.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Pacjent)) {
return false;
}
Pacjent other = (Pacjent) object;
if ((this.pesel == null && other.pesel != null) || (this.pesel != null && !this.pesel.equals(other.pesel))) {
return false;
}
return true;
}
@Override
public String toString() {
return "Pacjent[id=" + pesel + "]";
}
}
Zawarte w klasie TODO pozostawiam jako zadanie domowe dla dociekliwych - zapraszam do kontaktu, jeśli coś niejasne.
Klasa pl.jaceklaskowski.przychodnia.model.Wizyta
Kolejną klasą w modelu aplikacji Przychodnia jest pl.jaceklaskowski.przychodnia.beans.Wizyta. Modeluje ona wizyty pacjentów w przychodni.
package pl.jaceklaskowski.przychodnia.model;
import java.io.Serializable;
import java.util.Date;
public class Wizyta implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Pacjent pacjent;
private Date dzien;
private String objawy;
private String rozpoznanie;
private String leczenie;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Pacjent getPacjent() {
return pacjent;
}
public void setPacjent(Pacjent pacjent) {
this.pacjent = pacjent;
}
public Date getDzien() {
return dzien;
}
public void setDzien(Date dzien) {
this.dzien = dzien;
}
public String getLeczenie() {
return leczenie;
}
public void setLeczenie(String leczenie) {
this.leczenie = leczenie;
}
public String getObjawy() {
return objawy;
}
public void setObjawy(String objawy) {
this.objawy = objawy;
}
public String getRozpoznanie() {
return rozpoznanie;
}
public void setRozpoznanie(String rozpoznanie) {
this.rozpoznanie = rozpoznanie;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Wizyta)) {
return false;
}
Wizyta other = (Wizyta) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "Wizyta[id=" + id + "]";
}
}
Jak można zauważyć model aplikacji Przychodnia jest "technologicznie czysty", tzn. nie ma w nim nic technologicznie nadzwyczajnego poza użyciem konstrukcji języka Java. Przykładam duże znaczenie do czystości technologicznej aplikacji, których migracja do innych środowisk jest prostsza, a ponowne użycie ich elementów bezbolesne.
Krok 2: Projekt aplikacji javowej - przychodnia-generatortabel
Korzystanie z projektu Java Desktop Application w NetBeans IDE 6.1 uprości nam stworzenie aplikacji, ale do poprawnej jego pracy wymagana jest właściwa struktura tabel w bazie danych. W poprzednim kroku stworzyłem klasy, które będą (podkreślam, że wciąż jeszcze nie są) encjami JPA. W pomocniczym projekcie przychodnia-generatortabel zdefiniuję dwie encje JPA - Pacjent oraz Wizyta - i z odpowiednią konfiguracją JPA utworzę tabele podczas uruchomienia aplikacji. Projekt przychodnia-generatortabel będzie zwykłą aplikacją javową bez jakichkolwiek wodotrysków (poza samym użyciem JPA). Jej jedynym zadaniem jest utworzenie tabel w bazie, na podstawie których stworzę docelową aplikację desktopową.
Tym razem korzystam z typu projektu Java Application w kategorii Java w NetBeans IDE 6.1
o konfiguracji:
- Project Name: przychodnia-generatortabel
- Create Main Class: pl.jaceklaskowski.przychodnia.GeneratorTabel
Zatwierdzam przyciskiem Finish.
Konfiguracja zależności projektowej od projektu przychodnia-model
Projekt przychodnia-generatortabel będzie korzystał z klas utworzonych w projekcie przychodnia-model. Związuję oba projekty przez zdefiniowanie zależności między nimi. Zaznaczając projekt przychodnia-generatortabel wybieram z menu pod prawym klawiszem myszy - Properties i dalej Libraries, gdzie wciskam Add Project... i wskazuję na katalog projektu przychodnia-model.
Dodaję również biblioteki pomocnicze przez Add Library... jak Java DB Driver (sterownik JDBC dla przemianowanego Apache Derby) oraz TopLink Essentials ("sterownik" JPA).
Zatwierdzam przyciskiem OK.
Klasa pl.jaceklaskowski.przychodnia.GeneratorTabel
Zmieniam główną klasę aplikacji pomocniczej - pl.jaceklaskowski.przychodnia.GeneratorTabel (po utworzeniu jej podczas tworzenia projektu, w jej ciele, korzystam z asystenta Persistence > Use Entity Manager).
package pl.jaceklaskowski.przychodnia;
import pl.jaceklaskowski.przychodnia.model.Pacjent;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class GeneratorTabel {
public static void main(String[] args) {
new GeneratorTabel().persist(new Pacjent("73081300000", "Jacek", "Laskowski", "123456789"));
}
public void persist(Object object) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("przychodnia-derbyPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
try {
em.persist(object);
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
} finally {
em.close();
}
}
}
Plik konfiguracyjny JPA - META-INF/persistence.xml
Stworzenie konfiguracji JPA zacznę od pliku META-INF/persistence.xml, w którym zdefiniuję połączenie do bazy danych (Apache Derby aka Java DB w trybie wbudowanym). Konfiguracja JPA jest w projekcie pomocniczym, ale można wyobrazić sobie, że owa konfiguracja będzie również w docelowej aplikacji desktopowej, którą tworzę.
Ctrl+N, Persistence > Persistence Unit i podaję:
- Persistence Unit Name: przychodnia-derbyPU
- Database Connection: jdbc:derby:c:/temp/przychodnia-derby;create=true
Połączenie z bazą danych tworzę w ramach definicji PU przez wybór New Database Connection... w polu z listą rozwijalną Database Connection.
I tu jedna uwaga związana z działaniem NetBeans IDE 6.1 oraz sposobem, w jaki wbudowana baza danych działa ze ścieżkami względnymi. Jeśli w Database Connection podam ścieżkę względną położenia bazy danych, np. przychodnia-derby, wtedy uruchomienie aplikacji spowoduje utworzenie katalogu z bazą danych w katalogu bieżącym aplikacji, podczas gdy z poziomu NetBeans IDE ów katalog stworzony będzie odszukiwany w podkatalogu %USERPROFILE%/.netbeans/6.1/derby. Mimo, że w obu sytuacjach będzie można skorzystać z bazy danych to będą one różnymi bazami danych i sprawdzenie ich danych dałoby różny wynik (najprawdopodobniej nic nie istniałoby w tej NetBeansowej, bo aplikacja korzystałaby z innej bazy niż tą, którą sprawdzałbym). Rozwiązaniem jest stosowanie ścieżek względnych, bądź korzystanie z konfiguracji bazy danych w trybie sieciowym jako samodzielnej bazy danych.
W tym konkretnym przypadku opcja Table Generation Strategy mogłaby przyjmować wartości Create (utwórz struktury bazodanowe jak nie istnieją) lub Drop and Create (twórz struktury bazodanowe przy każdorazowym uruchomieniu aplikacji). Wybieram drugą opcję Drop and Create, z którą każdorazowe uruchomienie aplikacji rozpocznie się od utworzenia struktur bazodanowych.
Dodaję do utworzonego pliku META-INF/persistence.xml dostępne w projekcie przychodnia-model klasy pl.jaceklaskowski.przychodnia.model.Pacjent oraz pl.jaceklaskowski.przychodnia.model.Wizyta, co ostatecznie daje (tryb XML):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="przychodnia-derbyPU" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<class>pl.jaceklaskowski.przychodnia.model.Pacjent</class>
<class>pl.jaceklaskowski.przychodnia.model.Wizyta</class>
<properties>
<property name="toplink.jdbc.url" value="jdbc:derby:c:/temp/przychodnia-derby;create=true"/>
<property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
Plik konfiguracyjny mapowania JPA - META-INF/orm.xml
W pliku META-INF/orm.xml zawieram konfigurację mapowania klas pl.jaceklaskowski.przychodnia.model.Pacjent oraz pl.jaceklaskowski.przychodnia.model.Wizyta jako encje Pacjent i Wizyta z punktu widzenia JPA.
Ctrl+N, XML > XML Document i podaję dane:
- File Name: orm
- Folder: src\META-INF
Następnie Next > i Finish. Wklejam do niego poniższą treść (to była ta wiedza o JPA, która zniwelowała u mnie konieczność poznawania dogłębnie SQL - zapewne użycie adnotacji JPA znacznie uprościłoby mapowanie i faktycznie uzasadniłoby jego zastosowanie w porównaniu do tworzenia skryptów SQL).
<?xml version="1.0" encoding="UTF-8" ?> <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0"> <description>Kartoteka</description> <package>pl.jaceklaskowski.przychodnia.model</package> <entity class="Pacjent" name="Pacjent" metadata-complete="false"> <description>Encja Pacjent</description> <named-query name="znajdzPacjentaPoPeselu"> <query>SELECT p FROM Pacjent p WHERE p.pesel LIKE :pesel</query> </named-query> <attributes> <id name="pesel" /> <one-to-many name="wizyty" mapped-by="pacjent"> <cascade> <cascade-all /> </cascade> </one-to-many> </attributes> </entity> <entity class="Wizyta" name="Wizyta" metadata-complete="false"> <description>Encja Wizyta</description> <attributes> <id name="id"> <generated-value generator="AUTO"/> </id> <basic name="dzien"> <temporal>DATE</temporal> </basic> <many-to-one name="pacjent" /> </attributes> </entity> </entity-mappings>
Na uwagę zasługuje mapowanie relacji jeden-do-wielu Pacjent-Wizyta, w której zdefiniowałem dwukierunkową relację (element many-to-one w definicji encji Wizyta) ze wskazaniem na stronę wiodącą relacji (atrybut mapped-by). Bez tej "specjalnej" konfiguracji mapowania relacji jeden-do-wielu jako dwustronnej zostałaby utworzona tabela pośrednia związująca pacjentów z ich wizytami na podstawie klucz obcych do odpowiednich tabel reprezentujących encje Pacjent i Wizyta, a to z kolei nie pozwoliłoby skorzystać z możliwości asystenta projektu Java Desktop Application w pełni, bo wizyty nie byłyby rozpatrywane przy generowaniu aplikacji i nie pojawiłoby się miejsce ich edycji.
Uruchomienie aplikacji pomocniczej
Przyszła pora sprawdzić działanie encji i aplikacji pomocniczej, która przy uruchomieniu utworzy mi wymagane struktury bazodanowe.
F6 i po chwili na konsoli pojawia się BUILD SUCCESSFUL (total time: 5 seconds).
Jako zapewnienie, że wszystko zadziałało poprawnie skorzystam z zakładki Services, gdzie w sekcji Databases podłączam się do bazy danych przychodnia-derby (menu Connect...) i sprawdzam dostępność oraz zawartość tabel PACJENT i WIZYTA.
UWAGA: Wspominałem o tym, ale warto zrobić to ponownie. Należy stosować ścieżki bezwzględne w persistence.xml oraz zakładce Services, np. c:/temp/przychodnia-derbydb, aby możliwe było korzystanie z tej samej bazy danych, gdyż w przyciwnym przypadku uruchomienie aplikacji stworzy bazę danych w katalogu projektu, podczas gdy w zakładce Services będzie wskazanie na inną bazę danych (która dzięki create=true zostanie stworzona, jeśli nie istnieje).
UWAGA: Należy rozłączyć się od bazy danych, gdyż tryb wbudowany Apache Derby (aka Java DB) pozwala wyłącznie na pojedyńcze otwarte połączenie (menu Disconnect pod prawy przyciskiem myszki). W przeciwnym przypadku niemożliwe będzie podłączenie się do niej przy tworzeniu projektu Java Desktop Application.
Krok 3: Projekt aplikacji desktopowej - przychodnia
Ctrl+Shift+N, Java > Java Desktop Application i podaję następujące dane:
- Project Name: przychodnia
- Application Class: pl.jaceklaskowski.przychodnia.Przychodnia
- Choose Application Shell: Database Application
Wciskam przycisk Next > i w panelu Master Table wybieram zdefiniowane wcześniej połączenie do bazy danych, bądź definiuję nowe za pomocą New Database Connection.... Połączenie musi odpowiadać bazie danych, z której korzystaliśmy w projekcie pomocniczym przychodnia-generatortabel, który utworzył mi wymagane struktury bazodanowe.
i pole Database Table ustawiam na tabelę PACJENT jako tabelę wiodącą w aplikacji (w zasadzie to nie trzeba będzie tego robić, bo pole będzie już ustawione właściwie po wyborze połączenia).
Wciskam Next >.
W Detail Options wybieram WIZYTA (PACJENT_PESEL references PACJENT.PESEL) z listy w polu Table.
To jest właśnie ten moment, w którym wybieram szczegóły pacjenta (jego wizyty), które nie byłyby dostępne bez wspomnianej dwukierunkowej relacji jeden-do-wielu między encjami Pacjent a Wizyta.
Wciskam Finish.
Należy jeszcze sprawdzić biblioteki wykorzystywane przez aplikację, gdyż nie raz przytrafiło mi się napotkać błąd kompilacji bądź uruchomienia właśnie z braku niektórych. Rozwiązaniem jest dodanie bibliotek Java DB Driver oraz TopLink Essentials (Properties > Libraries > Add Library...).
Krok 4: Uruchomienie
Teraz wystarczy F6 (uruchomienie projektu głównego, który po utworzeniu projektu Java Desktop Application jest projektem przychodnia) i tworzenie aplikacji zakończone!
Co?! Wyjątek?! A może taki?
[TopLink Info]: 2008.05.16 08:09:26.343--ServerSession(14222419)--TopLink, version: Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))
2008-05-16 20:09:26 org.jdesktop.application.Application$1 run
SEVERE: Application class pl.jaceklaskowski.przychodnia.Przychodnia failed to launch
Local Exception Stack:
Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Uruchomienie bazy danych 'c:/temp/przychodnia-derby' nie powiodło się. Szczegóły zawiera następny wyjątek.
Error Code: 40000
at oracle.toplink.essentials.exceptions.DatabaseException.sqlException(DatabaseException.java:305)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:102)
at oracle.toplink.essentials.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:184)
at oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:582)
at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:280)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:229)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:93)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:126)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:120)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:91)
at pl.jaceklaskowski.przychodnia.PrzychodniaView.initComponents(PrzychodniaView.java:336)
at pl.jaceklaskowski.przychodnia.PrzychodniaView.<init>(PrzychodniaView.java:39)
at pl.jaceklaskowski.przychodnia.Przychodnia.startup(Przychodnia.java:19)
at org.jdesktop.application.Application$1.run(Application.java:171)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
Caused by: java.sql.SQLException: Uruchomienie bazy danych 'c:/temp/przychodnia-derby' nie powiodło się. Szczegóły zawiera następny wyjątek.
at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection.newSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection.bootDatabase(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection.<init>(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection30.<init>(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection40.<init>(Unknown Source)
at org.apache.derby.jdbc.Driver40.getNewEmbedConnection(Unknown Source)
at org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
at org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
at java.sql.DriverManager.getConnection(DriverManager.java:582)
at java.sql.DriverManager.getConnection(DriverManager.java:154)
at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:100)
... 20 more
Caused by: java.sql.SQLException: Uruchomienie bazy danych 'c:/temp/przychodnia-derby' nie powiodło się. Szczegóły zawiera następny wyjątek.
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
... 35 more
Exception in thread "AWT-EventQueue-0" java.lang.Error: Application class pl.jaceklaskowski.przychodnia.Przychodnia failed to launch
at org.jdesktop.application.Application$1.run(Application.java:177)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
Jeśli tak, to problem leży w już nawiązanym połączeniu do bazy danych Java DB, która w trybie wbudowanym akceptuje wyłącznie pojedyńcze połączenie. Jest to połączenie, które nawiązuje NetBeans, podczas tworzenia aplikacji przy zakładaniu projektu Java Desktop Application. Przechodzę do zakładki Services i wyłączam połączenie aplikacji Przychodnia - jdbc:derby:c:/temp/przychodnia-derby;create=true.
Ponownie F6 i....
Tym razem działa bezbłędnie! Pozostaje podmienić wygenerowane encje na te, zdefiniowane w projekcie przychodnia-model, ale to już pozostawiam czytelnikom jako pracę domową. Chętni do rozszerzenia artykułu proszeni są o kontakt na jacek@laskowski.net.pl.
Kompletny projekt aplikacji dostępny jest do pobrania jako netbeans-przychodnia-czesc1.zip.














