Java Enums та перевизначення методів

Читаючи книгу Programming Groovy, я дізнався про можливість перевизначати методи в enums. Про це навіть не здогадувався раніше, і це мене справді здивувало.
І справді, нехай у нас є enum в якому вказані дні в тижні:

enum DAYS {
MON, TUE,
WED, THU,
FRI, SAT,
SUN;

public String is() {
return "working";
}
}

Що ж, MON.is().equals("working") має бути істинним; але подібне тяжко сказати, наприклад, для SUN.is().equals("working").
Звичайно тепер ми можемо визначити enum наступним чином:

enum DAYS {
MON, TUE,
WED, THU,
FRI,
SAT {
public String is() {
return "week-end, day 1";
}
},
SUN {
public String is() {
return "week-end, day 2";
}
};

public String is() {
return "working";
}
}

І все, тепер SUN.is().equals("week-end, day 2") == true.
Проблема вирішена, при чому, без збереження зайвого поля - вказівника на рядок.

Mac OS X

Yesterday I have been fully moved to the Mac OS X. Spent all day for finding and installing software. I little bit sad, because can't find java 1.6 and 32 bit version.

I was thinking about changing used OS from Windows to Mac OS X or to Linux (Ubuntu) a very long time already. But just now found free day to move.
Still, If I'll not find the solution with java update and sound bad work then I'll become Linux (Ubuntu) user.

Google App Engine & Java

Google нарешті таки вирішив, що наступна версія App Engine буде підтримувати Java. З самого початку пора. А ще би було добре позбутися декотрих дивних обмежень, як от, тривалість запиту, маскимальний розмір файлу тощо.

SoftReference & WeakReference: time of life

Well, I found some free time to write few articles. This one is about the SoftReference class from Java library.
SoftReference will help you to get the best variant between using memory and performance. Soft reference means that the value wrapped in soft reference will be garbage collected only and only if there are no free memory.
More about this. First I set -verbose:gc parameter for Java machine. If this parameter is set than GC logs will be output to the console. Also was set parameter -Xmx32m. The simple code:

void test() {
Reference<List> listRef = new SoftReference<List>(
Arrays.asList("1", "2", "3", "4", "5"));

List list = new LinkedList();
for (int i = 1; i <= 5; i++) {
list.add(new Object());

if (i == 5) {
if (listRef.get() == null) {
break;
}
i = 1;
}
}
}

Here the soft reference to the long string was created. The loop adds the references to the object to the linked list. Sometimes it checks whether the soft reference to the list of strings is not gc'ed; if it is than loop is breaked. Here is the output of GC:

[GC 896K->708K(5056K), 0.0059887 secs]
[GC 1604K->1603K(5056K), 0.0064902 secs]
[GC 2499K->2498K(5056K), 0.0064698 secs]
[GC 3394K->3393K(5056K), 0.0062198 secs]
[GC 4289K->4287K(5184K), 0.0061248 secs]
[Full GC 4287K->4287K(5184K), 0.0378679 secs]
[GC 5120K->5119K(8000K), 0.0141557 secs]
[GC 6015K->6014K(8000K), 0.0069241 secs]
[GC 6910K->6908K(8000K), 0.0064464 secs]
[GC 7804K->7804K(8768K), 0.0061396 secs]
[Full GC 7804K->7804K(8768K), 0.0595140 secs]

We may see that more than one Full GC were run before the soft reference was cleaned up.
The same test for the WeakReference (change new SoftReference(...) into new WeakReference(...)) prints next output:

[GC 896K->707K(5056K), 0.0063061 secs]

So, weak reference is cleaned up after the next first GC runs.
These tests were made on Java 1.6.0_10.
The outputs for Java 1.5.0_07 are respectively

[GC 512K->387K(1984K), 0.0047419 secs]
[GC 899K->898K(1984K), 0.0046456 secs]
[GC 1410K->1409K(1984K), 0.0048894 secs]
[GC 1921K->1920K(2496K), 0.0046743 secs]
[Full GC 1920K->1920K(2496K), 0.0203305 secs]
[GC 2431K->2430K(3776K), 0.0103943 secs]
[GC 2942K->2941K(3776K), 0.0048556 secs]
[GC 3453K->3452K(4032K), 0.0047855 secs]
[Full GC 3452K->3452K(4032K), 0.0340532 secs]
[GC 3964K->3963K(6332K), 0.0044411 secs]
[GC 4475K->4474K(6332K), 0.0049126 secs]
[GC 4986K->4985K(6332K), 0.0046232 secs]
[GC 5497K->5496K(6332K), 0.0045682 secs]
[GC 6008K->6007K(6588K), 0.0047892 secs]
[Full GC 6007K->6007K(6588K), 0.0523812 secs]
[GC 6775K->6774K(10848K), 0.0061404 secs]
[GC 7542K->7540K(10848K), 0.0065743 secs]
[GC 8308K->8307K(10848K), 0.0067296 secs]
[GC 9075K->9074K(10848K), 0.0066386 secs]
[GC 9842K->9841K(10848K), 0.0066439 secs]
[GC 10609K->10608K(11488K), 0.0066955 secs]
[Full GC 10608K->10606K(11488K), 0.1112694 secs]

and

[GC 512K->387K(1984K), 0.0049869 secs]


Since, these results show that Java 6 works with memory better than Java 5 and cleans up the soft reference faster than it is in Java 5.

Spring MVC + FreeMarker + Tiles 2

Може комусь і знадобиться ще. Тут описується як прикрутити Spring MVC та FreeMarker та Tiles 2 так, щоб вони жили та працювали разом.
Задача: Tiles2 повинен організовувати шаблони створені на основі FreeMarker (хоча можна і не тільки FreeMarker, можна поєднувати). Для того, щоб досягнути це необхідно виконати декотру конфігурацію. У файлі web.xml

<servlet>
<servlet-name>pages</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>pages</servlet-name>
<url-pattern>*.page</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>

<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
</init-param>
<init-param>
<param-name>NoCache</param-name>
<param-value>true</param-value>
</init-param>
<init-paramv
<param-name>ContentType</param-name>
<param-value>text/html</param-value>
</init-param>

....

<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>

А тепер конфігурація pages-servlet.xml:

<!-- Конфігурація Tiles -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/defs/general.xml</value>
<value>/WEB-INF/defs/secure.xml</value>
</list>
</property>
</bean>

<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
</bean>

<!-- Контролер повертає view = /layout/header -->
<bean name="/layout/header.page" class="au.com.at2.web.spring.HeaderController"/>

Частина файла general.xml, в якому описуються оголошення Tiles:

<definition name="home" extends="default">
<put-attribute name="title" value="Home Page"/>
<put-attribute name="body" value="/templates/home.ftl"/>
</definition>
<definition name="default" template="/templates/main.ftl">
<put-attribute name="header" value="/layout/header.page"/>
<put-attribute name="footer" value="/templates/layout/footer.ftl"/>
</definition>
<definition name="/layout/header" template="/templates/layout/header.ftl"/>

Невеличке пояснення:
Спочатку добавив новий сервлет для FreeMarker'а. Всі шаблони в мене наразі стоять в каталозі templates, в той час, як TemplatePath для FreeMarker'а - це /. Я це зробив собі на майбутнє - для добавлення нових каталогів крім templates, - адже аплікація має розширюватися (вони завжди розширюються).
В pages-servlet.xml добавив bean tilesConfigurer, який будує конфігурацію для Tiles. Оголошення же знаходяться у файлах /WEB-INF/defs/general.xml, /WEB-INF/defs/secure.xml. При конфігурації інформація із них мерджеться, отже, оголошення default є доступним і в межах secure.xml.


<put-attribute name="header" value="/layout/header.page"/>

Цей кусок значить - можна використовувати як тайл і сторінку, що обробляється DispatcherServlet, таким чинном, ми можемо мати окремі контролери для окреми тайлів. І це правильно. Без цього би було туго. Контролер au.com.at2.web.spring.HeaderController повертає view /layout/header, який оголошений як definition в general.xml.