2011-10-06
2011-05-17
Jeszcze raz Groovy i Spring
Jakiś czas temu miałem problem z dynamiczną rekompilacją komponentów Spring napisanych w Groovy. Wtedy przyczyną był błąd w samym Groovy, szczegóły opisałem tutaj. Po aktualizacji Groovy wszystko było ok, ale niedawno stwierdziłem że mechanizm dynamicznego przeładowywania znowu przestał działać. Ponieważ w międzyczasie wykonałem spory refactoring aplikacji, to nie bardzo wiedziałem gdzie zacząć szukać sprawcy. Uznałem, że tym razem to nie Groovy - skoro raz zrobili błąd i go poprawili, to szansa na to że znowu się pojawił jest niewielka. Po włączeniu logów na poziomie DEBUG stwierdziłem, że Spring też jest niewinny - gdy plik źródłowy Groovy był zmieniany, w logach pojawiał się spodziewany komunikat:
Target refreshed successfully
... czyli skrypt był ładowany od nowa. Pomimo tego w aplikacji dalej używana była pierwotna wersja. Nie będę zanudzał Czytelnika szczegółowym opisem trudności i niebezpieczeństw, którym musiałem stawić czoła aby odkryć istotę problemu i przejdę od razu do clou tego posta. Tym razem bruździł Tomcat, a dokładnie jego ClassLoader.
Jeżeli skrypt zostanie umieszczony w aplikacji webowej w katalogu WEB-INF/classes i będziemy się do niego odwoływać w Springu tak:
<lang:defaults refresh-check-delay="1000"/> <lang:groovy id="myBean" source="classpath:Bean.groovy"/>... to po pierwszym wczytaniu Tomcat umieści plik Bean.groovy w cache i do restartu go nie ruszy. Co ciekawe Spring potrafi zauważyć zmianę daty ostatniej modyfikacji pliku i próbuje go ponownie wczytać, ale ClassLoader cały czas zwraca pierwotnie wczytaną wersję. Wystarczy przenieść plik do WEB-INF i zmienić wpis w konfiguracji na:
<lang:defaults refresh-check-delay="1000"/> <lang:groovy id="myBean" source="/WEB-INF/Bean.groovy"/>... by wszystko wróciło do normy. Spring wczytuje wtedy plik za pośrednictwem ServletContextu a nie ClassLoadera i dostaje zaktualizowaną wersję. Howgh.
2010-12-06
Użycie widoków w Hibernate
Spieszę donieść, iż błąd uniemożliwiający użycie @SecondaryTable w klasie bazowej, na który utyskiwałem w tym wpisie został w końcu poprawiony (po czterech latach od zgłoszenia!). Uaktualniłem projekt i rzeczywiście Hibernate w wersji 3.5.4 poprawnie obsługuje mapowanie bazowej encji na wiele tabel. Trafiłem jednak na kolejny problem i - w przeciwieństwie do opisywanego wcześniej - nie bardzo widzę sposób na obejście go.
Mając tabele i widok:
i klasę:
nie jesteśmy w stanie zapisać do bazy obiektu tej klasy. Pomimo, że jedyny atrybut zamapowany na widok jest tylko do odczytu (insertable i updatable równe false), to Hibernate próbuje wstawić dane do widoku, co kończy się wyjątkiem:
Widać że się stara (bo w wygenerowanym SQLu nie ma kolumny READ_ONLY), ale do końca mu nie wychodzi (bo jednak próbuje wstawić do widoku wiersz nie zawierający żadnych danych). I zupełnie nie mam pomysłu co na to poradzić.
Mając tabele i widok:
CREATE TABLE `TB_SOME_TABLE` (
`ID_PARENT` INT(11) NOT NULL AUTO_INCREMENT,
`READ_WRITE` TEXT,
PRIMARY KEY (`ID_PARENT`)
)
CREATE TABLE `TB_OTHER_TABLE` (
`PARENT_ID` INT(11) NOT NULL,
`SOME_DATA` TEXT
)
CREATE VIEW `VW_SOME_VIEW` AS
SELECT
`T`.`PARENT_ID` AS `PARENT_ID`,
COUNT(`T`.`PARENT_ID`) AS `READ_ONLY`
FROM
`TB_OTHER_TABLE` `T`
GROUP BY
`T`.`PARENT_ID`
i klasę:
@Entity
@Table(name = "TB_SOME_TABLE")
@SecondaryTable(
name = "VW_SOME_VIEW"
pkJoinColumns = @PrimaryKeyJoinColumn(name = "PARENT_ID")
)
public class Parent {
@Id
@Column(name = "ID_PARENT")
private Long id;
@Basic
@Column(name = "READ_WRITE, table = "TB_SOME_TABLE")
private String readWriteAtribute;
@Basic
@Column(
name = "READ_ONLY", table = "VW_SOME_VIEW",
insertable = false, updatable = false
)
private String readOnlyAttribute;
...
}
nie jesteśmy w stanie zapisać do bazy obiektu tej klasy. Pomimo, że jedyny atrybut zamapowany na widok jest tylko do odczytu (insertable i updatable równe false), to Hibernate próbuje wstawić dane do widoku, co kończy się wyjątkiem:
Unhandled exception 'JDBC exception on Hibernate data access:
SQLException for SQL [insert into VW_SOME_VIEW (PARENT_ID) values (?)];
SQL state [HY000]; error code [1471]; could not insert: [Parent]
Widać że się stara (bo w wygenerowanym SQLu nie ma kolumny READ_ONLY), ale do końca mu nie wychodzi (bo jednak próbuje wstawić do widoku wiersz nie zawierający żadnych danych). I zupełnie nie mam pomysłu co na to poradzić.
2010-10-26
Krótko
Nabyłem drogą kupna Photoshopa (Elements oczywiście). Wiem: ekstrawagancja i burżuazja, ale czasami mi się to zdarza. Ale ja nie o tym chciałem. Rzeczony Photoshop został wysyłany przez Amazon UK DHLem za darmo (od niedawna Free Super Saver Delivery obejmuje też Polskę) i kosztował 280 PLN. W naszym rodzimym sklepie, np. przysłowiowym Vobisie kosztuje 399 PLN. Rrrwa mać po trzykroć.
2010-10-17
Icon Finder
data publikacji 2010-10-17
(
2 komentarze
)
Nie raz i nie dwa pisząc program lub tworząc stronę internetową potrzebowałem różnego rodzaju ikon. Podstawowe kryteria, które musiały spełniać to: estetyczne, spójne i last but not least legalne. Bardzo ładnym i obszernym zestawem są Crystal Icons (licencja LGPL), ale jednak nie do wszystkiego pasują - są odrobinę zbyt śliczne. Drugi zestaw z którego tu i ówdzie korzystałem to Mini Icons ze strony famfamfam.com - prościutkie, małe ikonki idealne do użycia w aplikacjach webowych, ale jest ich tylko 144 i nie zawsze znajdzie się to czego potrzeba.
Dzisiaj trafiłem na stronę Icon Finder. W tej chwili jest tam 645 zestawów, 188325 ikon! I przede wszystkim możliwość wygodnego wyszukiwania bo wszystkie ikonki mają przypisane tagi (np. "red", "arrow", "left"). Mój ulubiony na dzień dzisiejszy zestaw to Simplico (licencja Creative Commons).


