<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-131947665105489199</id><updated>2012-01-29T16:15:19.567+02:00</updated><category term='mobile'/><category term='Intellij Idea'/><category term='synctab'/><category term='tools'/><category term='Performance'/><category term='Architecture'/><category term='documentation'/><category term='cache'/><category term='jaxb'/><category term='web'/><category term='comics'/><category term='Hibernate'/><category term='maven'/><category term='CI'/><category term='github'/><category term='psql'/><category term='Programming'/><category term='presentation'/><category term='grails'/><category term='Code Generation'/><category term='git'/><category term='python'/><category term='BlazeDS'/><category term='browser'/><category term='Mac OS X'/><category term='windows'/><category term='Flex'/><category term='uml'/><category term='Apache'/><category term='Spring'/><category term='Book'/><category term='jquery mobile'/><category term='Android'/><category term='Tiles 2'/><category term='News'/><category term='lazy loading'/><category term='linux'/><category term='facebook'/><category term='JasperReports'/><category term='JMeter'/><category term='JVM'/><category term='mysql'/><category term='Freemarker'/><category term='ramfs'/><category term='PermGen'/><category term='ffmpeg'/><category term='Кешування (Caching)'/><category term='bookmarks'/><category term='website'/><category term='Java'/><category term='django'/><category term='RichFaces'/><category term='Google'/><category term='AOSA'/><category term='Open Source'/><category term='webservice'/><category term='Portlet'/><category term='refcardz'/><category term='Apache Commons'/><category term='groovy'/><category term='FP'/><category term='html'/><category term='tmpfs'/><category term='memcached'/><category term='spring ws'/><category term='Patterns'/><category term='statistics'/><category term='ubuntu'/><category term='Scalable'/><category term='management'/><category term='subversion'/><title type='text'>Ruslan's blog</title><subtitle type='html'>software developer thoughts</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>81</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8819868529621652595</id><published>2011-11-24T21:02:00.001+02:00</published><updated>2011-11-24T21:28:28.715+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Android Emulator Snapshot</title><content type='html'>Here I'm going to describe a simple way to decrease a start up time of the Android Emulator. This is possible after snapshot saving and loading option is enabled.&lt;br /&gt;&lt;br /&gt;Open your terminal and enter the command:&lt;br /&gt;&lt;code&gt;&lt;br /&gt; $ android&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Open &lt;i&gt;Android Virtual Device Manager&lt;/i&gt; from menu Tools -&gt; Manage AVDs... You'll see a window like this:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="https://lh3.googleusercontent.com/-0Q9pA1qxId4/Ts6YroaqJBI/AAAAAAAAAsc/hfpSyw5EMOw/s667/Screenshot-Android%252520Virtual%252520Device%252520Manager%252520.png" alt="AVD Manager" width="450"/&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Select your working AVD from the list and click on "Edit" button. In the opened dialog check on to enable Snapshot. Save changes. Then click on the "Start..." button and check "Launch from snapshot" and "Save to snapshot" options. &lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="https://lh6.googleusercontent.com/-HcdsVI7N1cg/Ts6YrjiNf1I/AAAAAAAAAsg/TaQnJ_9iCHM/s369/Screenshot-Launch%252520Options%252520.png" alt="Launch options" width="200"/&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;If you haven't enabled "Saving to snapshot" option before, it may take a time to start the emulator first time. After it is started, you can close it and start again. This time emulator will be started much faster.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8819868529621652595?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8819868529621652595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8819868529621652595' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8819868529621652595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8819868529621652595'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/11/android-emulator-snapshot.html' title='Android Emulator Snapshot'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh3.googleusercontent.com/-0Q9pA1qxId4/Ts6YroaqJBI/AAAAAAAAAsc/hfpSyw5EMOw/s72-c/Screenshot-Android%252520Virtual%252520Device%252520Manager%252520.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-265622269491773697</id><published>2011-11-22T20:29:00.001+02:00</published><updated>2011-11-22T21:24:14.332+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open Source'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><category scheme='http://www.blogger.com/atom/ns#' term='AOSA'/><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'>MOBI version of The Architecture of Open Source Applications book</title><content type='html'>&lt;a href="http://www.aosabook.org/en/index.html"&gt;The Architecture of Open Source Applications&lt;/a&gt; is a great book where one can find the description of the architecture of the 25 open source applications, like Eclipse, LLVM, Mercurial, HDFS and Berkley DB. This book is free to read in the HTML format online, but if you want to get a PDF or Kindle version, you'll need to buy it either at Lulu.com or at Amazon.com.&lt;br /&gt;&lt;br /&gt;Of course &lt;strong&gt;the recommended way is to buy the book, as all royalties from these sales will be donated to Amnesty International&lt;/strong&gt;. But you can download a MOBI version for Kindle of this book for free, just continue reading.&lt;br /&gt;&lt;br /&gt;First, want to tell a short story. After I found a free SICP version for Kindle compiled from HTML files at &lt;a href="https://github.com/twcamper/sicp-kindle"&gt;github.com/twcamper/sicp-kindle&lt;/a&gt;, I was looking for a chance to create something like that myself. And then I found the AOSA book. It has an HTML version, and I wanted to have a MOBI version to read it in my Kindle.&lt;br /&gt;&lt;br /&gt;And so I made a Kindle version of The Architecture of Open Source Applications book and currently it's available from &lt;a href="https://github.com/rkhmelyuk/aosa-mobi"&gt;github.com/rkhmelyuk/aosa-mobi&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="https://github.com/rkhmelyuk/aosa-mobi/blob/master/aosa.mobi"&gt;Download a Kindle version of the AOSA&lt;/a&gt;&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-265622269491773697?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/265622269491773697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=265622269491773697' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/265622269491773697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/265622269491773697'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/11/mobi-version-of-architecture-of-open.html' title='MOBI version of The Architecture of Open Source Applications book'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6785633409356082287</id><published>2011-11-17T21:12:00.001+02:00</published><updated>2011-11-17T22:05:29.013+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='synctab'/><category scheme='http://www.blogger.com/atom/ns#' term='bookmarks'/><title type='text'>SyncTab</title><content type='html'>I've released today an updated version of a &lt;a href="http://synctab.khmelyuk.com"&gt;SyncTab&lt;/a&gt; Android application. &lt;br /&gt;&lt;br /&gt;Well, a few words about what is a SyncTab. SyncTab is an application to send an interesting links and browser tabs from Android phone to desktop browser (current only Chrome is supported). To start using SyncTab, user need only to download and install &lt;a href="https://market.android.com/details?id=com.khmlabs.synctab"&gt;Android application&lt;/a&gt; and &lt;a href="https://chrome.google.com/webstore/detail/hjjpbgkpgdfnjkgbghajpgcnaolcfcgf"&gt;Chrome extension&lt;/a&gt;. User will need to register an account using either Android application or Chrome extension and then he/she can easily send tabs from phone to desktop. There is more information about this in the &lt;a href="http://synctab.khmelyuk.com/help/getting-started"&gt;Getting Started&lt;/a&gt; article.&lt;br /&gt;&lt;br /&gt;So what's new in the version 0.6? Not much:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;added an about page to show current user name, website link, link to submit issue or contact&lt;/li&gt;&lt;li&gt;get the correct page title and description with regards to the page charset&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;But I have more plans for version 0.7:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;share tabs from browser to the phone&lt;/li&gt;&lt;li&gt;tag and filter shared tabs&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So try &lt;a href="http://synctab.khmelyuk.com/download"&gt;SyncTab&lt;/a&gt; now, and wait for a new features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6785633409356082287?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6785633409356082287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6785633409356082287' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6785633409356082287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6785633409356082287'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/11/synctab.html' title='SyncTab'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6177496566128320435</id><published>2011-11-03T00:31:00.000+02:00</published><updated>2011-11-03T00:38:54.417+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='synctab'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery mobile'/><title type='text'>Mobile website with jQuery Mobile</title><content type='html'>In my &lt;a href="http://blog.khmelyuk.com/2011/11/mobile-website-with-django.html"&gt;previous post&lt;/a&gt; I've described how to add support of mobile version of website using django. In this post I'm going to stop on front-end side of mobile website.&lt;br /&gt;&lt;br /&gt;From the beginning, I wanted to create a simple mobile version from scratch and use a similar to original website look. But, after some investigation, I've changed my plans. I decided to use some framework to create a mobile website. So I found two popular such frameworks: &lt;a href="http://www.sencha.com/products/touch/"&gt;Sencha Touch&lt;/a&gt; and &lt;a href="http://jquerymobile.com/"&gt;jQuery Mobile&lt;/a&gt;. Whilst Sencha Touch looks awesome and production ready, while jQuery Mobile is still in release candidate stage, I stopped on the second one. This choice was very simple for me: jQuery products usually are qualitative, there is a strong community behind them and they introduce new versions very quick. Nevertheless Sencha Touch is a good product too.&lt;br /&gt;&lt;br /&gt;I'm not going to describe how I used jQuery Mobile step by step, but only list of some facts and tips. First of all, I was using jQuery Mobile version 1.0 RC2, and that means, it wasn't a production-ready version yet. Even so, I found a few bugs or maybe just  a things that need an improvement.&lt;br /&gt;&lt;br /&gt;I just love such structures as lists. So will list a fact using a list =).&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You should read a manual first and follow a standard layout mechanism, like declare header, content and footer sections. This will save you a lot of time.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1335025.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none;"&gt;&amp;lt;div data-role="page"&amp;gt;&lt;br /&gt;           &amp;lt;div data-role="header"&amp;gt;&lt;br /&gt;               &amp;lt;a href="{% url m_home %}" data-icon="home" class="ui-btn-left"&amp;gt;Home&amp;lt;/a&amp;gt;&lt;br /&gt;               &amp;lt;a href="{% url m_help %}" data-icon="help" class="ui-btn-right"&amp;gt;Help&amp;lt;/a&amp;gt;&lt;br /&gt;              {% block header %} &amp;lt;h1&amp;gt;[App Name]&amp;lt;/h1&amp;gt;{% endblock %}&lt;br /&gt;           &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;           &amp;lt;div data-role="content"&amp;gt;&lt;br /&gt;            {% block content %}{% endblock %}&lt;br /&gt;           &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;           &amp;lt;div id="footer" data-role="footer"&amp;gt;  Copyright &amp;copy 2011 ... &amp;lt;/div&amp;gt;&lt;br /&gt;       &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It's a good practice to add Home/Back and Help buttons to the header or footer panel. The navigation bar can be also added to the header, where it looks very natural:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1335037.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none;" &gt;&amp;lt;div data-role="header"&amp;gt;&lt;br /&gt;   &amp;lt;a href="{% url m_home %}" data-icon="home" class="ui-btn-left"&amp;gt;Home&amp;lt;/a&amp;gt;&lt;br /&gt;   &amp;lt;a href="{% url m_help %}" data-icon="help" class="ui-btn-right"&amp;gt;Help&amp;lt;/a&amp;gt;&lt;br /&gt;   {% block header %}&amp;lt;h1&amp;gt;[AppName]&amp;lt;/h1&amp;gt;{% endblock %}&lt;br /&gt;&lt;br /&gt;   &amp;lt;div data-role="navbar"&amp;gt;&lt;br /&gt;      &amp;lt;ul&amp;gt;&lt;br /&gt;         &amp;lt;li&amp;gt;&amp;lt;a href="{% url m_download %}"&amp;gt;Download&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;         &amp;lt;li&amp;gt;&amp;lt;a href="{% url m_contact %}"&amp;gt;Contact&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;         ...&lt;br /&gt;      &amp;lt;/ul&amp;gt;&lt;br /&gt;   &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Fixed position of header and footer isn't working as it's expected. Well, expected it to be fixed always, while content is scrolling. But currently it just disappears when user starts scrolling and shows back after a second or so scrolling is ended.&lt;/li&gt;&lt;li&gt;Hash anchor links (#something) aren't working yet.&lt;/li&gt;&lt;li&gt;Can't show an image as a page, instead shows an "undefined" text. If you have a links that reference images, you must specify &lt;code&gt;rel="external"&lt;/code&gt; for them.&lt;/li&gt;&lt;li&gt;Use header to specify page title, rather than do it in the &lt;code&gt;h1&lt;/code&gt; element in the content section.&lt;/li&gt;&lt;li&gt;Use collapsible blocks for long pages. For instance, I've found them very helpful to organize a help page with many different topics.&lt;br /&gt;&lt;script src="https://gist.github.com/1335061.js"&gt; &lt;/script&gt;&lt;br /&gt;You may also want to embrace collapsible blocks using collapsible set.&lt;/li&gt;&lt;li&gt;For large image, don't show original version of it on page, but prefer thumbnail image as a link to the original version of image.&lt;/li&gt;&lt;li&gt;Use list view where possible. For instance, a main help page contains a list of articles which are references to the appropriate pages.&lt;/li&gt;&lt;li&gt;Buttons should be with icons where possible. You can easily add icon to the button with the &lt;code&gt;data-icon="[icon]"&lt;/code&gt; attribute. The list of available icons is &lt;a href="http://jquerymobile.com/demos/1.0rc2/docs/buttons/buttons-icons.html"&gt;on jQuery Mobile website&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Make website as simple as possible: structure should be simple, navigation bar should contain only the most used links. Remember, that it's still hard to work fully with websites on mobiles.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Well, that's all as for now. Hope that would be helpful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6177496566128320435?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6177496566128320435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6177496566128320435' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6177496566128320435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6177496566128320435'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/11/mobile-website-with-jquery-mobile.html' title='Mobile website with jQuery Mobile'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4165684294420125625</id><published>2011-11-03T00:29:00.002+02:00</published><updated>2011-11-03T00:31:17.314+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='synctab'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Mobile website with Django</title><content type='html'>Although I'm not a web guy, but more specialized on backend logic, I had a very interesting experience today creating a website version for mobiles. I had a simple website with a few pages, minimum server side logic and a slice of documentation there. This website perfectly works for desktop and tablet browsers, but is not that good for mobiles. I use to call this website as "normal" version throughout this post. It's important to have a working mobile version of website, as website is about Android application.&lt;br /&gt;&lt;br /&gt;A little bit about technologies and task. Website is running on Django as well as mobile version should be too. Mobile version of website should be much simpler than normal version, not so beautiful, but must do own job well: allow users to know about the product, download and access to the documentation. &lt;br /&gt;&lt;br /&gt;I decided to use the same django application for both normal and mobile website versions. I found a few different ways to add mobile website, for example: redirect to another django application, replace &lt;code&gt;TEMPLATE_DIRS&lt;/code&gt; setting with a version that points to mobile templates if user is using mobile browser or just check and use different logic/templates in every view method. As I wanted to have a different structure for mobile website, I decided to go by my own way.&lt;br /&gt;&lt;br /&gt;Mobile website path should be prefixed with &lt;code&gt;/m/&lt;/code&gt; rather than be the same or use a different domain name. So, if normal website download page is &lt;code&gt;http://example.com/download/&lt;/code&gt;, then mobile download page should be &lt;code&gt;http://example.com/m/download/&lt;/code&gt;. Django should check every user request whether it's from mobile browser or not using a User-Agent metadata, and if so, redirect to the mobile version of the page. In other words, if user opens a &lt;code&gt;/download/&lt;/code&gt; page from mobile browser, then she will be redirected to the &lt;code&gt;/m/download/&lt;/code&gt; page. But if she opens a &lt;code&gt;/m/download&lt;/code&gt; page, then no redirects happen - just a mobile version of page is returned to user. &lt;br /&gt;&lt;br /&gt;I've created different templates and views for mobile version of website. Normal version of website has references only to the normal pages and mobile version of website has references only to the mobile pages. This was done to avoid not necessary redirects that could slow down a work with website. Thus, I had a different version of URL patterns for website in project's &lt;code&gt;urls.py&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1334937.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none;"&gt;urlpatterns = patterns('website.views',&lt;br /&gt;    url(r'^$', 'home', name='home'),&lt;br /&gt;    url(r'^download/$', 'download', name='download'),&lt;br /&gt;    url(r'^screenshots/$', 'screenshots', name='screenshots'),&lt;br /&gt;    url(r'^contact/$', 'contact', name='contact'),&lt;br /&gt;    ... &lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;urlpatterns += patterns('website.mobile',&lt;br /&gt;    url(r'^m/$', 'home', name='m_home'),&lt;br /&gt;    url(r'^m/download/$', 'download', name='m_download'),&lt;br /&gt;    url(r'^m/screenshots/$', 'screenshots', name='m_screenshots'),&lt;br /&gt;    url(r'^m/contact/$', 'contact', name='m_contact'),&lt;br /&gt;    ...&lt;br /&gt;)&lt;br /&gt;&lt;/pre&gt;As you see, &lt;code&gt;website.views&lt;/code&gt; are responsible for handling normal website pages, while &lt;code&gt;website.mobile&lt;/code&gt; for handling mobile website pages.&lt;br /&gt;&lt;br /&gt;Now need to redirect mobile browser users to the mobile version of website. For this purpose, I wrote a custom middleware called &lt;code&gt;MobileWebsiteMiddleware&lt;/code&gt;. The task of this middleware is to check if user is from a popular mobile platform and needs to be redirected to the mobile version of website. The other responsibility is to redirect users from mobile to the normal version of website in case if request isn't from mobile browser. This is an extract option, that should be disabled while testing.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1334967.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;class MobileWebsiteMiddleware(object):&lt;br /&gt;&lt;br /&gt;    MOBILE_PREFIX = '/m/'&lt;br /&gt;    MOBI_REG = re.compile(&lt;br /&gt;        '(iphone|windows ce|mobile|phone|symbian|mini|pda|ipod|mobi|blackberry|playbook|vodafone|kindle)',&lt;br /&gt;        re.IGNORECASE)&lt;br /&gt;&lt;br /&gt;    def process_request(self, request):&lt;br /&gt;&lt;br /&gt;        if 'HTTP_USER_AGENT' in request.META:&lt;br /&gt;            userAgent = request.META.get('HTTP_USER_AGENT')&lt;br /&gt;            matches = self.MOBI_REG.search(userAgent)&lt;br /&gt;            path = request.path_info&lt;br /&gt;&lt;br /&gt;            if matches:&lt;br /&gt;                # from mobile browser, check if need to redirect to mobile&lt;br /&gt;                if not path.startswith(self.MOBILE_PREFIX):&lt;br /&gt;                    # need to redirect to mobile version&lt;br /&gt;                    return HttpResponseRedirect('/m' + path)&lt;br /&gt;            elif path.startswith(self.MOBILE_PREFIX):&lt;br /&gt;                    # need to redirect to normal version&lt;br /&gt;                    return HttpResponseRedirect(path[2:])&lt;br /&gt;&lt;br /&gt;        return None&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you'll check the list list of user agent patterns in &lt;code&gt;MOBI_REG&lt;/code&gt; you wouldn't find neither iPad nor Android. I want to show a "normal" website for tablets. "Android" keyword is used in User Agent for both mobiles and tablets. While &lt;strong&gt;Mobile Android&lt;/strong&gt; browsers pass a User Agent with a "mobile" keyword, but &lt;strong&gt;Tablet Android&lt;/strong&gt; browsers don't do that. Thus, I will have a normal version for desktop and tablets browsers, but mobile version for mobiles and Kindle.&lt;br /&gt;&lt;br /&gt;Now I have a simple website, that has two different version: one for desktop and tablet browsers and another for mobile browsers. User will be automatically redirected to the right version of website which depends on used device. &lt;br /&gt;&lt;br /&gt;In my &lt;a href="http://blog.khmelyuk.com/2011/11/mobile-website-with-jquery-mobile.html"&gt;next post&lt;/a&gt; I'm going to tell more about using jQuery Mobile to build a mobile version of website.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4165684294420125625?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4165684294420125625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4165684294420125625' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4165684294420125625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4165684294420125625'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/11/mobile-website-with-django.html' title='Mobile website with Django'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1461753898718953931</id><published>2011-10-31T21:55:00.000+02:00</published><updated>2011-10-31T21:55:49.954+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Django: use global variables on rendering templates</title><content type='html'>&lt;h3&gt;Problem&lt;/h3&gt;Some settings or global value is used in every template or, for example, in base layout template. This value should be passed as context variable to each template. I call such value a global context variable in this post.&lt;br /&gt;&lt;br /&gt;For instance, it can be a Google Analytics Code, which should be used in production, but not in staging or development environments. In this case, it’s fine to move GA code to the settings file (of course, if different settings used for different environments). Though need to find a way to get the value from the settings and pass it to the template context before rendering.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Solutions&lt;/h3&gt;There are a few simple solutions that solve the described problem:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add global variable to the template context in every view. But according to &lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY&lt;/a&gt; and good sense this is a bad solution.&lt;/li&gt;&lt;li&gt;Write a tag to fetch setting value by name and output it. Nice solution and flexible enough in case we need to show different settings in different pages. The only disadvantage is fetching setting value each time it’s accessed. But in most cases this is a minor.&lt;/li&gt;&lt;li&gt;Write a context processor. In the documentation said that &lt;strong&gt;context processor&lt;/strong&gt; is a method that takes a request object as argument and returns a dictionary of items to be merged into the context. In other words, context processor returns a dictionary of items that will be available in template on render phase. In our case, we can get setting value and return from our own context processor method. &lt;br /&gt;&lt;script src="https://gist.github.com/1328606.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none;"&gt;from django.conf import settings&lt;br /&gt;&lt;br /&gt;def global_vars(request):&lt;br /&gt;    return {'GA_CODE': settings.GA_CODE}&lt;br /&gt;&lt;/pre&gt;Also, need to declare our context processor in &lt;code&gt;settings.TEMPLATE_CONTEXT_PROCESSORS&lt;/code&gt;:&lt;br /&gt;&lt;script src="https://gist.github.com/1328609.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;TEMPLATE_CONTEXT_PROCESSORS = (&lt;br /&gt;   . . . &lt;br /&gt;   'synctab.website.context_processors.global_vars',&lt;br /&gt;)&lt;br /&gt;&lt;/pre&gt;From now, GA_CODE context variable can be used in any template, and will be processed correctly.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;In my opinion, the best decision for fixed list of globally accessed template context variables is a custom context provider. It's also a right way, if most or all templates use same global variables. Otherwise, it's good to write a few tags to cover access to the global state, like settings.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1461753898718953931?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1461753898718953931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1461753898718953931' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1461753898718953931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1461753898718953931'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/10/django-use-global-variables-on.html' title='Django: use global variables on rendering templates'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5278493756230655063</id><published>2011-10-14T12:04:00.001+03:00</published><updated>2011-10-14T12:04:25.136+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Intellij Idea'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='tmpfs'/><category scheme='http://www.blogger.com/atom/ns#' term='website'/><category scheme='http://www.blogger.com/atom/ns#' term='cache'/><category scheme='http://www.blogger.com/atom/ns#' term='ramfs'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>tmpfs: work with your data even faster</title><content type='html'>Currently improving IDEA performance by copying cache files into the RAM using &lt;i&gt;tmpfs&lt;/i&gt;. Actually, &lt;i&gt;tmpfs&lt;/i&gt; and &lt;i&gt;ramfs&lt;/i&gt; are good ideas.&lt;br /&gt;&lt;br /&gt;As described &lt;a href="http://en.wikipedia.org/wiki/Tmpfs"&gt;in Wikipedia&lt;/a&gt;: &lt;i&gt;&lt;b&gt;tmpfs&lt;/b&gt; is intended to appear as a mounted file system, but stored in volatile memory instead of a persistent storage device&lt;/i&gt;. Simply put, when you copy a file to such FS, this means that you copy a file to the RAM. When you create a file in this FS, this means you create a file in RAM. When you delete a file in this FS, this means you delete a file in a RAM. And so on.&lt;br /&gt;&lt;br /&gt;The negative side of &lt;i&gt;tmpfs&lt;/i&gt; is that it's not backed by any storage: on restart or system crash you'll lost your files and data stored in &lt;i&gt;tmpfs&lt;/i&gt;. But on system start you can either copy files from the disk to the memory again and continue to work.&lt;br /&gt;&lt;br /&gt;In case of IDEA cache, I will need to write a simple script that periodically copies the cache from &lt;i&gt;tmpfs&lt;/i&gt; to the disk. So, on restart, I can simply restore cache, and don't need to wait while re-caching is done.&lt;br /&gt;&lt;br /&gt;So, how to create a tmpfs storage? It's pretty easy to do with next commands. Here I create an empty directory &lt;code&gt;tmp&lt;/code&gt; and mount it as tmpfs filesystem.&lt;br /&gt;&lt;pre&gt;# mkdir ~/tmp&lt;br /&gt;# mount -t tmpfs -o size=500m tmpfs ~/tmp&lt;br /&gt;&lt;/pre&gt;Option &lt;code&gt;size=500m&lt;/code&gt; limits memory usage to 500m. tmpfs also supports flushing content to the swap when need. This is one of the main differences between &lt;i&gt;tmpfs&lt;/i&gt; and &lt;i&gt;ramfs&lt;/i&gt;. &lt;i&gt;ramfs&lt;/i&gt; is not limited and can grow dynamically, and the used memory can't be freed or flush to swap. The negative side of such dynamic nature of &lt;i&gt;ramfs&lt;/i&gt; is that system can hung when no free memory left. &lt;br /&gt;&lt;br /&gt;To read from and write content to RAM is much much faster than to do the same operations with a file on disk. It's pretty good optimization if you need to support read-only content or content that can easily be restored when need.&lt;br /&gt;&lt;br /&gt;Such type of content is a hosted website. You can decrease page or resource loading time by moving them from hard disk to the memory filesystem.&lt;br /&gt;&lt;pre&gt; # mkdir /var/www/www.example.com&lt;br /&gt; # mount -t tmpfs -o size=50M tmpfs /var/www/www.example.com&lt;br /&gt; # cp -R /home/www/www.example.com/* /var/www/www.example/com&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To mount &lt;i&gt;tmpfs&lt;/i&gt; automatically on system load, you will need to add another record to yours &lt;code&gt;/etc/fstab&lt;/code&gt; configuration file. The only you need to do now is execute next command on system start:&lt;br /&gt;&lt;pre&gt; # cp -R /home/www/www.example.com/* /var/www/www.example/com&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As a summary, &lt;i&gt;tmpfs&lt;/i&gt; is a good way to work with large amount of files or data that need to be accessed or processed quickly. Such data also is either read-only or can be easily recreated. Samples of such data are static websites, website resources, temporary cache etc. When need to process large amount of data, you can also split it into small pieces and process each one by one. &lt;i&gt;tmpfs&lt;/i&gt; is also takes a limited amount of RAM, and can increase over that amount.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5278493756230655063?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5278493756230655063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5278493756230655063' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5278493756230655063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5278493756230655063'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/10/tmpfs-work-with-your-data-even-faster.html' title='tmpfs: work with your data even faster'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7537252938331666661</id><published>2011-10-11T15:47:00.001+03:00</published><updated>2011-10-11T15:51:39.720+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Performance Optimization for Android</title><content type='html'>Here is the list of the performance optimization tips when developing Android applications:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Avoid creating objects if you don’t need them.&lt;/li&gt;&lt;li&gt;Avoid memory allocation if you can work without it.&lt;/li&gt;&lt;li&gt;Array of ints is preferred than array of Integers.&lt;/li&gt;&lt;li&gt;Two parallel arrays of ints are a lot more efficient than an array of (int,int) objects. Two parallel arrays of Foo and Bar are a lot more efficient than an array of (Foo,Bar) objects.&lt;/li&gt;&lt;li&gt;Avoid creating short-term temporary objects if you can.&lt;/li&gt;&lt;li&gt;Make your method static. Invocations will be about 15%-20% faster. It's also good practice, because you can tell from the method signature that calling the method can't alter the object's state.&lt;/li&gt;&lt;li&gt;It's reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly.&lt;/li&gt;&lt;li&gt;Direct field access is about 7x faster than invoking a trivial getter.&lt;/li&gt;&lt;li&gt;Use static final for constants.&lt;/li&gt;&lt;li&gt;Prefer for-each loop.&lt;/li&gt;&lt;li&gt;Declare fields and methods accessed by inner classes to have package access, rather than private access.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Read &lt;a href="http://developer.android.com/guide/practices/design/performance.html"&gt;Designing for Performance&lt;/a&gt; article from Android Dev Guide to find more details and samples.&lt;br /&gt;&lt;br /&gt;List also available as &lt;a href="https://gist.github.com/1277969"&gt;gist&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7537252938331666661?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7537252938331666661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7537252938331666661' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7537252938331666661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7537252938331666661'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/10/performance-optimization-for-android.html' title='Performance Optimization for Android'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5012859638977759253</id><published>2011-10-05T17:20:00.000+03:00</published><updated>2011-10-05T21:42:00.135+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CI'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><title type='text'>Rename of GitHub account and Deploy Keys</title><content type='html'>Today I've fixed failed builds that were caused by renaming GitHub account. Bamboo couldn't pull the changes from GitHub master repository after rename.&lt;br /&gt;&lt;br /&gt;So, I corrected the account name in the &lt;code&gt;.git/config&lt;/code&gt; file for origin remote. But this didn't help - I had same the same problem to pull the changes. &lt;br /&gt;&lt;br /&gt;That was a security problem: GitHub denied access to the repository, because I don't have access to the old repository (of course, that because account name was changed).&lt;br /&gt;&lt;br /&gt;After some investigation, I decided to drop existing Deploy Key and create the same again. &lt;br /&gt;And Voilà! This small manipulation fixed the problem with access to the GitHub repository and now builds are green again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5012859638977759253?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5012859638977759253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5012859638977759253' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5012859638977759253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5012859638977759253'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/10/rename-github-account-and-deploy-keys.html' title='Rename of GitHub account and Deploy Keys'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total><georss:featurename>Ivano-Frankivsk, Ukraine</georss:featurename><georss:point>48.922633 24.711117</georss:point><georss:box>48.880899 24.632153000000002 48.964366999999996 24.790081</georss:box></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7735435304494958805</id><published>2011-09-11T20:11:00.001+03:00</published><updated>2011-09-11T20:11:20.832+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='bookmarks'/><category scheme='http://www.blogger.com/atom/ns#' term='browser'/><title type='text'>Hightlights: How Browsers Work</title><content type='html'>&lt;style type="text/css"&gt; .citation { padding-left: 10px; font-size: 13px; font-style: italic; color: #777777; margin: 20px 0 10px 0; border-left: 8px solid #efefef; line-height: 22px; }&lt;/style&gt;&lt;p&gt; This is a short summary of great article &lt;a href="http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/"&gt;How Browses Work&lt;/a&gt; by &lt;a href="http://taligarsiel.com/"&gt;Tali Garsiel&lt;/a&gt;.  My opinion that it is a must-read article not only for web developers, but for everyone who want to know how browsers work.&lt;/p&gt;&lt;p&gt;I’m not a web developer, but was interesting in this article to know more about how browsers work inside. This article can help to understand the process of rendering html page, loading and processing CSS and JavaScript files by browser.&lt;/p&gt;Here I list of my highlights after reading How Browsers Read article:&lt;div class="citation"&gt;&lt;img src="http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/flow.png" alt="browser-render-workflow" title="Page rendering flow"/&gt;&lt;/div&gt;&lt;p&gt;As you can see, browser needs to build a few different trees: DOM tree, rendering tree, style rules tree, style context tree etc.&lt;/p&gt;&lt;div class="citation"&gt;The rendering engine will start getting the contents of the requested document from the networking layer. This will usually be done in 8K chunks.&lt;/div&gt;&lt;p&gt;To render a page faster, browser doesn’t wait while all page and css and scripts are loaded. Instead browser loads a chunk of html code, parse it and build a DOM and rendering trees. Then rendering tree is used to paint the page, so user can see it. If we know the size of chunk, we can predict how fast is html page processed. If the html page size is under 8K (or whatever specific browser limit), we should expect it to load much faster.&lt;/p&gt;&lt;div class="citation"&gt;For better user experience, the rendering engine will try to display contents on the screen as soon as possible. It will not wait until all HTML is parsed before starting to build and layout the render tree.&lt;/div&gt;&lt;div class="citation"&gt;The algorithm is expressed as a state machine. Each state consumes one or more characters of the input stream and updates the next state according to those characters. The decision is influenced by the current tokenization state and by the tree construction state. This means the same consumed character will yield different results for the correct next state, depending on the current state.&lt;/div&gt;&lt;p&gt;Special state machine used to parse HTML document. I was interesting how they parse HTML, because it’s pretty hard to parse such forgiving language. From this article it’s clear that state machine is used to parse the document. In article described:&lt;/p&gt;&lt;div class="citation"&gt;The input to the tree construction stage is a sequence of tokens from the tokenization stage The first mode is the"initial mode". Receiving the html token will cause a move to the "before html" mode and a reprocessing of the token in that mode. This will cause a creation of the HTMLHtmlElement element and it will be appended to the root Document object.The state will be changed to "before head". We receive the "body" token. An HTMLHeadElement will be created implicitly although we don't have a "head" token and it will be added to the tree.&lt;/div&gt;&lt;p&gt;Browsers use stack to order tags correctly and fix a mix of opened/closed tags. Opened tags are added to the stack, and when they are closed and corrected, they are inserted into the DOM tree. As result DOM tree is always in correct state. Different browsers handle new DOM elements differently: either provide dirty bit or fire events. While parsing document DOM elements are processed and added to the Rendering tree, that becomes a source for painting phase.&lt;/p&gt;&lt;div class="citation"&gt;When the parsing is finished browser will mark the document as interactive and start parsing scripts that are in "deferred" mode - those who should be executed after the document is parsed. The document state will be then set to "complete" and a "load" event will be fired.&lt;/div&gt;&lt;div class="citation"&gt;The model of the web is synchronous. Authors expect scripts to be parsed and executed immediately when the parser reaches a &amp;lt;script&amp;gt; tag. The parsing of the document halts until the script was executed. If the script is external then the resource must be first fetched from the network - this is also done synchronously, the parsing halts until the resource is fetched. This was the model for many years and is also specified in HTML 4 and 5 specifications. Authors could mark the script as "defer" and thus it will not halt the document parsing and will execute after it is parsed. HTML5 adds an option to mark the script as asynchronous so it will be parsed and executed by a different thread.&lt;/div&gt;&lt;p&gt;Asynchronous scripts can be loaded faster maybe even before page is rendered, because browser does not need to wait to load it. Still there is a single rendering thread, so after script is loaded, any changes to the tree will be applied and processed by main thread.&lt;/p&gt;&lt;div class="citation"&gt;While executing scripts, another thread parses the rest of the document and finds out what other resources need to be loaded from the network and loads them. This way resources can be loaded on parallel connections and the overall speed is better. Note - the speculative parser doesn't modify the DOM tree and leaves that to the main parser, it only parses references to external resources like external scripts, style sheets and images.&lt;/div&gt;&lt;p&gt;This is how browser can parse the document and load resources, like CSS, scripts and images.&lt;/p&gt;&lt;div class="citation"&gt;The style contexts contain end values. The values are computed by applying all the matching rules in the correct order and performing manipulations that transform them from logical to concrete values. For example - if the logical value is percentage of the screen it will be calculated and transformed to absolute units. The rule tree idea is really clever. It enables sharing these values between nodes to avoid computing them again. This also saves space.&lt;/div&gt;&lt;p&gt;As it said in article, handling style correctly was made very clever. A tree structure and other optimizations help to handle correctly styles inheritance and large number or styles properties.&lt;/p&gt;&lt;p&gt;In the article also said:&lt;/p&gt;&lt;div class="citation"&gt;All the matched rules are stored in a tree. The bottom nodes in a path have higher priority. The tree contains all the paths for rule matches that were found. Storing the rules is done lazily. The tree isn't calculated at the beginning for every node, but whenever a node style needs to be computed the computed paths are added to the tree.&lt;/div&gt;&lt;p&gt;As result, real values (like height, margin etc) for each style are not computed till they needed. &lt;/p&gt;&lt;div class="citation"&gt;After parsing the style sheet, the rules are added one of several hash maps, according to the selector. There are maps by id, by class name, by tag name and a general map for anything that doesn't fit into those categories. If the selector is an id, the rule will be added to the id map, if it's a class it will be added to the class map etc. This manipulation makes it much easier to match rules. There is no need to look in every declaration - we can extract the relevant rules for an element from the maps. This optimization eliminates 95+% of the rules, so that they need not even be considered during the matching process.&lt;/div&gt;&lt;p&gt;Hash maps are used as indexes. This is another performance optimization.&lt;/p&gt;&lt;div class="citation"&gt;Before repainting, webkit saves the old rectangle as a bitmap. It then paints only the delta between the new and old rectangles. &lt;/div&gt;&lt;p&gt;Well, another performance and usability optimization.&lt;/p&gt;&lt;div class="citation"&gt;The browsers try to do the minimal possible actions in response to a change. So changes to an elements color will cause only repaint of the element. Changes to the element position will cause layout and repaint of the element, its children and possibly siblings. Adding a DOM node will cause layout and repaint of the node. Major changes, like increasing font size of the "html" element, will cause invalidation of caches, relyout and repaint of the entire tree.&lt;/div&gt;Expected optimization - the larger change the more relayout and repaint is needed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7735435304494958805?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7735435304494958805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7735435304494958805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7735435304494958805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7735435304494958805'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/09/hightlights-how-browsers-work.html' title='Hightlights: How Browsers Work'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total><georss:featurename>Ivano-Frankivsk, Ukraine</georss:featurename><georss:point>48.915279853443806 24.70001220703125</georss:point><georss:box>48.581031853443804 24.06829820703125 49.24952785344381 25.33172620703125</georss:box></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1959159993867063826</id><published>2011-09-11T12:57:00.002+03:00</published><updated>2011-09-11T13:48:49.122+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='statistics'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Get Total Commits Number in Git</title><content type='html'>&lt;p&gt;In a few weeks there will be an anniversary as I've started working on current project. So I decided to find out the total number of made commits from the project begin. While it's obvious for Subversion, in Git you need something more that just look at the revision number.&lt;/p&gt;&lt;p&gt;First, I came out with a simple command that prints the total number of commits:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;$ git log --pretty=format:'%h' | wc -l&lt;br /&gt;&lt;/pre&gt;prints out &lt;pre&gt;&lt;br /&gt;2485&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This is a bit primitive and that wouldn't be such a simple solution if need to find the total number of commits per author.I didn't want to believe there is not better way to get the total number of commits per author with standard Git tool.&lt;/p&gt;&lt;p&gt;After a few minutes of research I found there is a simple and powerful util &lt;code&gt;git shortlog&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;So next command&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;$ git shortlog -n -s&lt;br /&gt;&lt;/pre&gt;prints out&lt;pre&gt;&lt;br /&gt;  2317  Ruslan Khmelyuk&lt;br /&gt;   104  Author_1&lt;br /&gt;    53  Author_2&lt;br /&gt;     9  unknown&lt;br /&gt;     2  Author_3&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I've summed the commit numbers for each committer and found that the total commits number by &lt;code&gt;git shortlog&lt;/code&gt; command is 2485 and that is equal to the result of &lt;code&gt;git log | wc -l&lt;/code&gt; command. While &lt;code&gt;git rev-list -all | wc -l&lt;/code&gt; command prints there are 2488 commits in the repository. Strange.&lt;/p&gt;&lt;p&gt;Short investigation helped me to understand that both commands working fine and show correct number. The difference between commands&lt;pre&gt;&lt;br /&gt;$ git log --pretty=format:'%h' | wc -l&lt;br /&gt;$ git shortlog -n -s&lt;br /&gt;&lt;/pre&gt;and &lt;pre&gt;&lt;br /&gt;$ git rev-list --all | wc-l&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;is in the source they're using to calculate commits list.&lt;/p&gt;&lt;p&gt;&lt;code&gt;git log&lt;/code&gt; and &lt;code&gt;git shortlog&lt;/code&gt; use current branch commits log, while &lt;code&gt;git rev-list&lt;/code&gt; uses all repository as source of commits list.I had 3 more commits in the other branch, so in my local repository I had in total 2488 commits.&lt;/p&gt;&lt;p&gt;Even more, If you need to calculate the total number of commits in the remote repository, you will need to use &lt;code&gt;git rev-list&lt;/code&gt; command:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;$ git fetch origin&lt;br /&gt;$ git rev-list --remotes | wc -l&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Thus I can say, that &lt;code&gt;git rev-list&lt;/code&gt; command works best to find out the total number of made commits.&lt;/strong&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1959159993867063826?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1959159993867063826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1959159993867063826' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1959159993867063826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1959159993867063826'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/09/git-total-commits-number.html' title='Get Total Commits Number in Git'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total><georss:featurename>Ukraine</georss:featurename><georss:point>48.4602778 24.5586111</georss:point><georss:box>48.4181588 24.4796471 48.5023968 24.6375751</georss:box></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-3879874180025687391</id><published>2011-08-21T12:45:00.004+03:00</published><updated>2011-08-21T12:51:20.121+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Кешування (Caching)'/><category scheme='http://www.blogger.com/atom/ns#' term='Freemarker'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='lazy loading'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Lazy loading on demand in CMS</title><content type='html'>&lt;strong&gt;Context:&lt;/strong&gt;&lt;br /&gt;Application is responsible for generating pages from templates. User can edit such templates to show data from storage. Data shown on the page are defined by template, each template can show separate set of data (for instance, news, tasks, articles etc.)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;br /&gt;How to render a user defined template correctly, so any provided by user or application data can be included into template in runtime and have a good performance of rendering?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br /&gt;Lets view the problem from MVC point:&lt;br /&gt;View is a template defined by user, and can use any data entered by user (news, blog articles, tasks etc.)&lt;br /&gt;Model is data that should be used by a template engine to render a View.&lt;br /&gt;Controller is a place where user can prepare the Model, that will be sent to a template engine to generate specified View.&lt;br /&gt;&lt;br /&gt;As we can’t predict what kind of data are used in any particular View (it could be news, blog articles etc.), the simplest implementation is to fetch all data from storage and push them as a Model to the template engine. In this case template engine will render a View correctly, as all required data are available from the Model. The bad side of this approach is a very slow performance as we need to fetch all data and put them as Model again and again for each request. The more data and different types of data we have to use to populate a Model, the more time this phase will take. &lt;br /&gt;&lt;br /&gt;Another approach is to analyze template on save or before render, to fetch all types of data we may need to render it right. For example, before saving a template, we found that it contains a references to blog articles and latest news. Although, we may need to run such operation only once and populate the model only with specified type of data, there is a large number of case not covered by this method: using predefined macros, including other templates and access to data that will be need in runtime, for instance: a single article with specified id, a list of latest 5 articles or anything else that need to be fetched dynamically.&lt;br /&gt;&lt;br /&gt;If we think more about the last case, where we need to fetch data dynamically, we will find that it's much easier and better to populate Model not with data, but with data access objects. Of course, in this case we will need to create these data access objects on each request, to pass a context to theme and use them while rendering, it’s still much better (and faster), then populate Model with all data.&lt;br /&gt;&lt;br /&gt;When I say a data access object, I don’t mean this object should get the data directly from database or any other storage. But I mean that this object can store request context and can access a restricted set of data, e.g. the list of news posted by current user only or the list of tasks that belongs to current user.&lt;br /&gt;&lt;br /&gt;OK, hope your engine template supports methods call and you can get the list of 5 latest news just as simple as saying &lt;code&gt;${news.latest(5)}&lt;/code&gt; or get current user information just with &lt;code&gt;${user.profile()}&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;But here I would like to propose another way to access those less dynamical data. For instance, we need to show  user profile information or list of active tasks. Of course, this can be done with appropriate DAO from Model, but there is another way.&lt;br /&gt;&lt;br /&gt;This another way helps to save templates clean, - without calling all those DAO methods, but also without prefetching data on the Controller side. This way is based upon a famous &lt;a href="http://en.wikipedia.org/wiki/Lazy_loading"&gt;Lazy Loading technique&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Although, this may look a bit harder to implement, it brings us a few valuable benefits. First of all, as I said before, code looks clean and easier for user to work with. It's much pleasant to write &lt;code&gt;${news.latest}&lt;/code&gt; than &lt;code&gt;${news.latest()}&lt;/code&gt; and &lt;code&gt;${user.profile.firstName}&lt;/code&gt; than &lt;code&gt;${user.profile().firstName}&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Second, and it's related to the lazy loading too, we load data once and only when it's needed. The emphasis in on the word 'once'. When we hit our object from the Model first time, it's loading data, which then are available since and to the end of rendering phase. So no matter, from what part of template you access it, it will use already loaded data without touching a storage again. When I say "any part of template", I mean it can be anything available in template engine: macro, function or included template. In this case, you don't need to use a variable or local cache to store loaded data, as you may need to do with data access objects.&lt;br /&gt;&lt;br /&gt;Third, lazy loaded data can be complex structures. For instance, we load a current user profile. Profile object is a structure that contains user names, characteristics, address, contact information and a list of followings profiles. Here, address and contact information are embedded objects, which are stored in separate tables/collections and list of followings is a reference to another a few profile objects. If you need to output user full name, you just don't want to load address information, contact information and list of followings. That's where we can also use lazy loading to save user time and server powers. We load address information when need, we load the list of followings when need, we load contact information of some following only when need.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In my next article I’m going to show a simple implementation of lazy loading technique for &lt;a href="http://freemarker.sourceforge.net/"&gt;FreeMarker&lt;/a&gt; template engine, which is my favourite one for many years.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-3879874180025687391?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/3879874180025687391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=3879874180025687391' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3879874180025687391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3879874180025687391'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/08/lazy-loading-on-demand-in-cms.html' title='Lazy loading on demand in CMS'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1764957109470692293</id><published>2011-08-04T12:45:00.004+03:00</published><updated>2011-08-04T12:55:07.091+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Neverending Groovy: compareTo() simple as it can be with &lt;=&gt;</title><content type='html'>Groovy introduced a new operator to compare two values: &lt;strong&gt;&lt;code&gt;&lt;=&gt;&lt;/code&gt;&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;When you use this operator for 2 values &lt;code&gt;a &lt;=&gt; b&lt;/code&gt;, Groovy translates this to code something like that &lt;code&gt;a.compareTo(b)&lt;/code&gt;. Well that's not the true, as it also can handle &lt;code&gt;null&lt;/code&gt; values correctly. So you wouldn't get &lt;code&gt;NPE&lt;/code&gt;, when you compare value with &lt;code&gt;null&lt;/code&gt; or vice versa. For instance, next script:&lt;br /&gt;&lt;script src="https://gist.github.com/1124841.js?file=blog_compare_to_op.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;&lt;br /&gt;a = null&lt;br /&gt;b = 12&lt;br /&gt;&lt;br /&gt;println "a.compareTo(b) = " + (a &lt;=&gt; b)&lt;br /&gt;println "a.compareTo(a) = " + (a &lt;=&gt; a)&lt;br /&gt;println "b.compareTo(b) = " + (b &lt;=&gt; b)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;outputs&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  a.compareTo(b) = -1&lt;br /&gt;  a.compareTo(a) = 0&lt;br /&gt;  b.compareTo(b) = 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where we can see, that &lt;code&gt;null&lt;/code&gt; values are handled correctly, without any runtime exceptions.&lt;br /&gt;&lt;br /&gt;With such operator we could write really nice and simple code to allow multiple comparisons for object values.&lt;br /&gt;&lt;br /&gt;Lets we have a class &lt;code&gt;Person&lt;/code&gt; with firstName, lastName and age data:&lt;br /&gt;&lt;script src="https://gist.github.com/1124842.js?file=blog_person_light.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;&lt;br /&gt;class Person {&lt;br /&gt;    String firstName&lt;br /&gt;    String lastName&lt;br /&gt;    int age&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And we need to sort a list of Persons by age, than by name (first by last name, than by first name). Assume, this is standard sorting mode, so we may prefer to implement &lt;code&gt;Comparable&lt;/code&gt; interface:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1124850.js?file=blog_person_comparable_empty.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;&lt;br /&gt;class Person implements Comparable&lt;Person&gt; {&lt;br /&gt;    String firstName&lt;br /&gt;    String lastName&lt;br /&gt;    int age&lt;br /&gt;&lt;br /&gt;    int compareTo(Person other) {&lt;br /&gt;      ...&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Method &lt;code&gt;compareTo()&lt;/code&gt; isn't implemented yet. So lets try to implement in Java first. It would look something like this:&lt;br /&gt;&lt;script src="https://gist.github.com/1124852.js?file=blog_compare_to_java_style.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;&lt;br /&gt;int compareTo(Person other) {&lt;br /&gt;        if (other == null) {&lt;br /&gt;            return 1;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        int result = 0;&lt;br /&gt;        if (this.age &gt; other.age) {&lt;br /&gt;            result = 1;&lt;br /&gt;        }&lt;br /&gt;        else if (this.age &lt; other.age) {&lt;br /&gt;            result = -1;&lt;br /&gt;        }&lt;br /&gt;        if (result == 0) {&lt;br /&gt;            if (this.lastName != null &amp;&amp; other.lastName != null) {&lt;br /&gt;                result = this.lastName.compareTo(other.lastName);&lt;br /&gt;                if (result == 0) {&lt;br /&gt;                    if (this.firstName != null &amp;&amp; other.firstName != null) {&lt;br /&gt;                        result = this.firstName.compareTo(other.firstName);&lt;br /&gt;                    }&lt;br /&gt;                    else {&lt;br /&gt;                        result = this.firstName != null ? 1 : -1;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            else {&lt;br /&gt;                result = this.lastName != null ? 1 : -1;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hm... Looks ugly! Too much &lt;code&gt;if&lt;/code&gt;'s, too much checks, too much 0, 1 and -1. &lt;i&gt;Hard to see the logic behind the code ((&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;And here how this can be written with Groovy's &lt;code&gt;&lt;=&gt;&lt;/code&gt; operator:&lt;br /&gt;&lt;script src="https://gist.github.com/1124853.js?file=blog_compare_to_groovy_style.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;&lt;br /&gt;  int compareTo(Person other) {&lt;br /&gt;        age &lt;=&gt; other.age ?: lastName &lt;=&gt; other.lastName ?: firstName &lt;=&gt; other.firstName&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And a simple test:&lt;br /&gt;&lt;script src="https://gist.github.com/1124857.js?file=blog_compare_to_person_test.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;pre style="display: none"&gt;&lt;br /&gt;def john = new Person(firstName: 'John', lastName: 'Doe', age: 25)&lt;br /&gt;def mark = new Person(firstName: 'Mark', lastName: 'White', age: 25)&lt;br /&gt;&lt;br /&gt;print "john &lt;=&gt; mark = " + (john &lt;=&gt; mark)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;prints &lt;pre&gt;&lt;br /&gt;  john &lt;=&gt; mark = -1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As for me, it looks wonderful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1764957109470692293?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1764957109470692293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1764957109470692293' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1764957109470692293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1764957109470692293'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/03/neverending-groovy-compareto-simple-as.html' title='Neverending Groovy: compareTo() simple as it can be with &lt;=&gt;'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-2145321521573686866</id><published>2011-05-15T23:16:00.007+03:00</published><updated>2011-05-15T23:32:14.178+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='memcached'/><category scheme='http://www.blogger.com/atom/ns#' term='documentation'/><category scheme='http://www.blogger.com/atom/ns#' term='cache'/><category scheme='http://www.blogger.com/atom/ns#' term='Scalable'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>"A Story of Caching"</title><content type='html'>I was playing with memcached a few days ago. Never used it before, so spent some time to read documentation and FAQ. &lt;br /&gt;&lt;br /&gt;While reading FAQ, I found the link to the page with &lt;a href="http://code.google.com/p/memcached/wiki/TutorialCachingStory"&gt;A Story of Caching&lt;/a&gt;, and decided to share link to this story here.&lt;br /&gt;&lt;br /&gt;IMHO, this is the best non-technical technical documentation, that I've read recently. In this story, they use simple but widespread use cases of developing web application and using cache in this web application.&lt;br /&gt;&lt;br /&gt;If you don't know what's for memcached, than read &lt;a href="http://code.google.com/p/memcached/wiki/TutorialCachingStory"&gt;this story&lt;/a&gt;. &lt;br /&gt;If you don't know what's the primary features of memcached, than read &lt;a href="http://code.google.com/p/memcached/wiki/TutorialCachingStory"&gt;this story&lt;/a&gt;. &lt;br /&gt;If you don't know if you need memcached, than read &lt;a href="http://code.google.com/p/memcached/wiki/TutorialCachingStory"&gt;this story&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-2145321521573686866?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/2145321521573686866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=2145321521573686866' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2145321521573686866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2145321521573686866'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/05/story-of-caching.html' title='&quot;A Story of Caching&quot;'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4048532335667887196</id><published>2011-03-22T12:02:00.005+02:00</published><updated>2011-04-03T13:50:53.206+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freemarker'/><title type='text'>Assign &lt;#nested&gt; to variable in FreeMarker</title><content type='html'>FreeMarker is awesome template engine. I'm still wonder how much powerful it is and how flexible it can be when you need. Last week, when I was writing a simple macro to render tweets using user defined template, my though was that it may be good to define this template as macro nested content. For instance:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;@tweets 'rkhmelyuk', 10&amp;gt;&lt;br /&gt;      [picture] [username]: &amp;lt;br/&amp;gt;&lt;br /&gt;      [message]&amp;lt;br/&amp;gt;&lt;br /&gt;      &amp;lt;a href="[url]"&amp;gt;[date]&amp;lt;/a&amp;gt;&lt;br /&gt;  &amp;lt;/@tweets&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pretty simple, but the only way for me was to load tweets using Twitter API through JSONP protocol. So my macro was need to generate a javascript code, that should correctly define callback and fetch tweets. Callback function simply applies received JSON data to the user defined template.&lt;br /&gt;&lt;br /&gt;And here is the problem. How to get macro's nested content into javascript variable? Well, who ever used FreeMarker knows that nested content can be rendered with command &lt;code&gt;&lt;#nested/&gt;&lt;/code&gt;. This could be a solution, but isn't. Why? Because I need to do extra preparing of template to put it as a javascript string. I need to remove newlines and replace quotes. So the best decision is to put nested content as Freemarker variable and do preparation over it first and than insert into javascript. And here is the power of Freemarker. This was possible and easy to do with &lt;code&gt;&lt;#assign/&gt; or &lt;#local/&gt;&lt;/code&gt; command:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &amp;lt;#local layout&amp;gt;&amp;lt;#nested/&amp;gt;&amp;lt;/#local&amp;gt;&lt;br /&gt; &amp;lt;#-- Now layout variable contains a template defined as nested --&amp;gt;&lt;br /&gt; &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;    function callback_${id}(data) {&lt;br /&gt;       var layout = "${layout?SomePreparationsGoHere}";&lt;br /&gt;       renderTweets(layout, data);&lt;br /&gt;    }&lt;br /&gt; &amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this code, the nested content is assigned to variable layout. Then we generates a javascript code and insert layout variable as string, but first do some preparations.&lt;br /&gt;&lt;br /&gt;I also like flexibility of Freemarker. I hope that could find a time and describe some other tips about it soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4048532335667887196?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4048532335667887196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4048532335667887196' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4048532335667887196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4048532335667887196'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/03/assign-to-variable-in-freemarker.html' title='Assign &lt;#nested&gt; to variable in FreeMarker'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8668253390360039795</id><published>2011-03-22T12:01:00.014+02:00</published><updated>2011-04-03T13:52:12.026+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='facebook'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Facebook was failing to parse OG meta tags</title><content type='html'>Last week was having awful time fighting with strange work of Facebook. We had a page with OG meta tags and a Facebook Like button on the page. And Facebook was discarding to parse the page and extract data from OG meta tags. Using URL linter didn't help to find the problem but show the same information - page isn't parsed, OG meta tags are not used.&lt;br /&gt;&lt;br /&gt;So I tried to check next things to find the issue:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;whether property attribute in used &amp;lt;meta/&amp;gt; tags&lt;/li&gt;&lt;br /&gt; &lt;li&gt;whether correct fb:app_id meta tag value is set&lt;/li&gt;&lt;br /&gt; &lt;li&gt;whether nginx returns correct page when facebook requests the page&lt;/li&gt;&lt;br /&gt; &lt;li&gt;whether correct namespaces added to the &amp;lt;html/&amp;gt; tag&lt;/li&gt;&lt;br /&gt; &lt;li&gt;whether we are using UTF-8 encoding&lt;/li&gt;&lt;br /&gt; &lt;li&gt;and something other, don't remember all my tests&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;And was checking web page through URL Linter each time. With no success. Facebook discarded parsing the page and fetching page title with other data from meta tags.&lt;br /&gt;&lt;br /&gt;So I reviewed response/request data through firebug to find suspicious things. I found one scanty detail: Content-Type header had value &lt;code&gt;"text/html;charset=utf-8;charset=UTF-8"&lt;/code&gt;. &lt;br /&gt;I must say, this one web page is generated by application using user-defined template. Grails controller is responsible for handling request and renders output like:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  render text: context.out, contentType: "text/html;charset=$AppConstant.RENDER_CHARSET"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;where &lt;code&gt;AppConstant.RENDER_CHARSET&lt;/code&gt; equals to "UTF-8". But the rendered page had Content-Type equal to "text/html;charset=utf-8;charset=UTF-8". And my thought was to fix header value to have something like "text/thml;charset=UTF-8" and hoped this may help. So I changed code to be like:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  render text: context.out, contentType: "text/html"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Content-Type header value now is "text/html;charset=utf-8". So I tried URL Lint again. I wasn't expecting much from Facebook this time either, but miracle happened! Everything works fine now. I know, that is my fault, but, nevertheless, thank you Facebook for "nice" time spending :).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8668253390360039795?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8668253390360039795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8668253390360039795' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8668253390360039795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8668253390360039795'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/03/facebook-was-failing-to-parse-og-meta.html' title='Facebook was failing to parse OG meta tags'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-3678840012165832924</id><published>2011-02-13T16:09:00.011+02:00</published><updated>2011-02-13T16:34:00.033+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Linux tools to generate password</title><content type='html'>Few days ago was looking for simple tool to generate passwords in linux console.&lt;br /&gt;As result of my searching are 3 useful tools. They are: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;apg&lt;/li&gt;&lt;br /&gt; &lt;li&gt;makepasswd&lt;/li&gt;&lt;br /&gt; &lt;li&gt;pwgen&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;apg&lt;/h3&gt;&lt;br /&gt;Install: &lt;code&gt;sudo apt-get install apg&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Asks to enter random data, that should be used to generate new password.&lt;br /&gt;Example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Please enter some random data (only first 16 are significant)&lt;br /&gt;(eg. your old password):&gt;&lt;br /&gt;Opt8Ovuf (Opt-EIGHT-Ov-uf)&lt;br /&gt;Uc1Gryec (Uc-ONE-Gryec)&lt;br /&gt;jadJoav5 (jad-Joav-FIVE)&lt;br /&gt;IshtIvawam3 (Isht-Iv-aw-am-THREE)&lt;br /&gt;lakVosAfUrg7 (lak-Vos-Af-Urg-SEVEN)&lt;br /&gt;dyijDus8 (dyij-Dus-EIGHT)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;You can pass random string as parameter and use many different options:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ apg -n 10 -m 8 -x 12 somerandomdata&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Will generate 10 passwords with min length 8 and max length 12.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;makepasswd&lt;/h3&gt;&lt;br /&gt;Install: &lt;code&gt;sudo apt-get install makepasswd&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Generates password, by default one. User may need to use options to set length of password and count of passwords. For example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ makepasswd --count=10 --minchars=5 --maxchars=10&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Results:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mzd4f9q&lt;br /&gt;gUWamL&lt;br /&gt;NYiUXrYvq3&lt;br /&gt;6hWDXKA&lt;br /&gt;gQpu20IJGD&lt;br /&gt;BSAT5ASFX&lt;br /&gt;37FcKyLPb&lt;br /&gt;ma7pC66A&lt;br /&gt;cFpWPBy&lt;br /&gt;0oTNhT7&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;pwgen&lt;/h3&gt;&lt;br /&gt;Install: &lt;code&gt;sudo apt-get install pwgen&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;My favorite tool to generate password. By default generates 160 different passwords each with length 8 symbol. Programs takes 2 parameters: &lt;br /&gt; - 1st is the length of the password and &lt;br /&gt; - 2nd is the count of passwords to generates. For example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ pwgen 12 24&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Results:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;oHo2iethieze cheiS6ohPeed Oozufiorohv9 eic3aethei4L hiRohYie6Ue4 aephoiDieb0y&lt;br /&gt;hieTh8eizaeK aid1EeNgaiSe yoh6chohX9ha aiPhae7dieMe wedooD8nai7y aic7deeB9eS8&lt;br /&gt;ohFor3Achied Thaequu4aiph zaeghiem7keT Shee5ooxaex0 wePh2eiNgien aicohroo2Go3&lt;br /&gt;Aagh0gahcah0 Zie8eazaitah aoha9AeXi7Bo Oojoob0oosh6 Olahgh4aeji6 oobae9UZ2phi&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-3678840012165832924?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/3678840012165832924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=3678840012165832924' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3678840012165832924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3678840012165832924'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2011/02/tools-to-generated-password.html' title='Linux tools to generate password'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4768195834539474882</id><published>2010-12-27T21:24:00.012+02:00</published><updated>2010-12-27T22:50:29.847+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Open Source'/><title type='text'>Open Source: core library</title><content type='html'>Few months ago, after I moved to GitHub, one of my util projects was open sourced. It was, simply called, core: &lt;a href="https://github.com/rkhmelyuk/core"&gt;https://github.com/rkhmelyuk/core&lt;/a&gt;. I have written this library few years ago and was actively using on Java projects. In some places it crosses with Apache Commons Lang library, but I, actually, like my child more :)&lt;br /&gt;&lt;br /&gt;I'd like to describe some key classes and show samples of use. Some of them are enumerated below.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/rkhmelyuk/core/blob/master/src/main/java/com/prutsoft/core/utils/StringUtils.java"&gt;StringUtils&lt;/a&gt; contains few oftenly used methods, like:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;&lt;code&gt;isEmpty(), isBlank(), isNotEmpty(), isNotBlank(), isBlankTrimmed(), isNotBlankTrimmed()&lt;/code&gt; - used to check whether string is empty or not. The difference between empty and blank, is that empty is either &lt;code&gt;null&lt;/code&gt; or empty string, while blank is always blank string and can't be &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;code&gt;cut()&lt;/code&gt; - used to cut string if length is more than specified and appends with specified suffix. The only difference is that this method tries to split by space, so don't cut the word. Sample:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;   String string = "some string goes here";&lt;br /&gt;   assertEquals "some string...", StringUtils.cut(string, 15, "...");&lt;br /&gt;&lt;/code&gt;&lt;br /&gt; &lt;li&gt;&lt;code&gt;trimIfNotNull()&lt;/code&gt; - if input string is not null, then trim it and return result:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  String string = "  Hello  ";&lt;br /&gt;  assertEqual "Hello", StringUtils.trimIfNotNull(string);&lt;br /&gt;  assertNull StringUtils.trimIfNotNull(null);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt; &lt;li&gt;&lt;code&gt;replaceNotAlphaNumeric()&lt;/code&gt; - replace all characters that are not letter or digit with specified one or "_" by default.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/rkhmelyuk/core/blob/master/src/main/java/com/prutsoft/core/utils/ConversionUtils.java"&gt;ConversionUtils&lt;/a&gt; contains some simple but useful methods to convert string value to numeric and boolean types. Contains methods &lt;code&gt;getInteger(), getLong(), getBoolean(), getDouble(), getDate(), getFloat()&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   assertEquals 1, ConversionUtils.getInteger("1");&lt;br /&gt;   assertNull ConversionUtils.getInteger("hello");&lt;br /&gt;   assertEquals 5, ConversionUtils.getInteger("hello", 5);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="https://github.com/rkhmelyuk/core/blob/master/src/main/java/com/prutsoft/core/KeyGenerator.java"&gt;KeyGenerator&lt;/a&gt; was created to generate API keys, passwords and other random stuff. It has one highly configurable method and few helpful methods that uses it. There is a way to generate keys with alpha and/or numeric and/or special symbols.&lt;br /&gt;&lt;br /&gt;That would be hard to write assertions for samples, but here are simple use cases:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  KeyGenerator.generateKey(10, KeyGenerator.WITH_ALPHA_LOW | KeyGenerator.WITH_ALPHA_UP);&lt;br /&gt;  KeyGenerator.generateStrongKey(100);&lt;br /&gt;  KeyGenerator.generateSimpleKey(20);&lt;br /&gt;  KeyGenerator.generateAlphaKey(20);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After &lt;a href="http://java-ua.blogspot.com/2009/07/tostringbuilder-and-multi-thread.html"&gt;I found some issues with Apache Commons-Lang ToStringBuilder&lt;/a&gt;, I wrote my own replacement, and called it... &lt;a href="https://github.com/rkhmelyuk/core/blob/master/src/main/java/com/prutsoft/core/ToStringBuilder.java"&gt;ToStringBuilder&lt;/a&gt; :) It is very simple in use:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   class Blog {&lt;br /&gt;      private String name;&lt;br /&gt;      private String author;&lt;br /&gt;      private int year;&lt;br /&gt;&lt;br /&gt;      public String toString() {&lt;br /&gt;          new ToStringBuilder(Blog.class)&lt;br /&gt;              .field("name", name)&lt;br /&gt;              .field("author", author)&lt;br /&gt;              .field("year", year)&lt;br /&gt;              .toString();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   Blog blog = new Blog();&lt;br /&gt;   blog.setName("Java UA");&lt;br /&gt;   blog.setAuthor("Ruslan Khmelyuk");&lt;br /&gt;   blog.setYear(2010);&lt;br /&gt;&lt;br /&gt;   assertEquals "Blog[name=Java UA, author=Ruslan Khmelyuk, year=2010]", blog.toString();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There are much more interesting tools, like &lt;a href="https://github.com/rkhmelyuk/core/blob/master/src/main/java/com/prutsoft/core/asserts/ArgumentAssert.java"&gt;ArgumentAssert&lt;/a&gt; and &lt;a href="https://github.com/rkhmelyuk/core/blob/master/src/main/java/com/prutsoft/core/asserts/StateAssert.java"&gt;StateAssert&lt;/a&gt; used to assert arguments and program state respectively.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/rkhmelyuk/core/blob/master/src/main/java/com/prutsoft/core/utils/collections/CollectionUtils.java"&gt;CollectionUtils&lt;/a&gt; also contains few useful methods, and I'm not going to describe them here. &lt;br /&gt;&lt;br /&gt;Library is open to review and use. Still it's definitely not the best one and, I think, has value only for me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4768195834539474882?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4768195834539474882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4768195834539474882' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4768195834539474882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4768195834539474882'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/12/open-source-core-library.html' title='Open Source: core library'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6860335540333285431</id><published>2010-12-16T23:04:00.006+02:00</published><updated>2010-12-16T23:19:32.761+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Neverending Groovy: map with default values</title><content type='html'>More and more Groovy openings for me every day!&lt;br /&gt;&lt;br /&gt;Just today, I found that there is a way to setup default value for map entry, if absent. In some cases it may be very handy. &lt;br /&gt;&lt;br /&gt;For example, I need to prepare a map with words counts. This simple task should be coded simple too, like:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def map = [:]&lt;br /&gt;words.each { word -&gt; map[word]++ }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;But it's not working and fails with NPE exception. Why? Because it's hard to increment &lt;code&gt;null&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Although, there is simple way to avoid this problem even using Groovy API:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def map = [:]&lt;br /&gt;words.each { word -&gt; map[word] &lt;strong&gt;= map.get('word', 0) + 1&lt;/strong&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Here 2nd parameter of &lt;code&gt;map.get()&lt;/code&gt; method is the default value, returned if there is no value for key 'word'. And now it's working fine! &lt;br /&gt;Still there is another way, and, as for me, it helps to make code clean and safe. Safe because default logic can be used elsewhere we want to use our map object.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def map = [:]&lt;strong&gt;.withDefault { 0 }&lt;/strong&gt;&lt;br /&gt;words.each { word -&gt; map[word]++ }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I bet there is a better way and I'm going to find it...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6860335540333285431?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6860335540333285431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6860335540333285431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6860335540333285431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6860335540333285431'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/12/neverending-groovy-map-with-default.html' title='Neverending Groovy: map with default values'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7144273721216292655</id><published>2010-11-15T17:55:00.006+02:00</published><updated>2010-11-15T18:05:45.814+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='psql'/><title type='text'>MySQL pager</title><content type='html'>I very liked to use &lt;code&gt;psql&lt;/code&gt; command. Among different usability things, it uses &lt;code&gt;less&lt;/code&gt; command to show query results. That was the thing I always wanted to have in &lt;code&gt;mysql&lt;/code&gt; command. And was sure that's not possible, and till today was suffered in silence.&lt;br /&gt;&lt;br /&gt;But today, quite unexpected for me, I found &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-command-options.html#option_mysql_pager"&gt;option pager&lt;/a&gt; for &lt;code&gt;mysql&lt;/code&gt; command. This option let me set the program, I want to use to see query search results. So, to use &lt;code&gt;less&lt;/code&gt; program, I was just need to start &lt;code&gt;mysql&lt;/code&gt; with &lt;code&gt;--pager&lt;/code&gt; parameter:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ mysql --pager=less&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;or in &lt;code&gt;mysql&lt;/code&gt; console:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mysql&gt; pager=less&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Now I'm happy to use it! And you should try too :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7144273721216292655?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7144273721216292655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7144273721216292655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7144273721216292655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7144273721216292655'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/11/mysql-pager.html' title='MySQL pager'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6249853213871895871</id><published>2010-11-13T23:33:00.005+02:00</published><updated>2010-11-13T23:55:14.852+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Neverending Groovy</title><content type='html'>Вже кілька місяців коджу в основному на Groovy. Прекрасна мова, прекрасна підтримка від IntelliJIdea. Часто знаходжу все нові і кращі спрособи реалізації деколи тривіальних речей. &lt;br /&gt;&lt;br /&gt;Для прикладу, необхідно отримати список із значень певного поля кожного елементу списку. Спочатку, я писав доволі простий і зрозумілий код, ясно ще під впливом Java:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;List&lt;String&gt; names = []&lt;br /&gt;for (Person person : persons) {&lt;br /&gt;   names &lt;&lt; person.firstName&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;З часом я удосконалювався і коду ставало менше:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def names = []&lt;br /&gt;persons.each { names &lt;&lt; it.firstName }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Виглядає дуже навіть зрозуміло, пишеться швидко і ще швидше читається.&lt;br /&gt;Але і це не був край досконалості, і трохи пізніше я почав писати вже:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def names = persons.collect { it.firstName }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;І цей кусок коду поражав мене тим, що був тільки 1 рядок, назва методу collect є зрозумілішою, ніж each у цьому конкретному випадку. І так, може, і писав би й дальше, якби не вирішив спробувати використати для цього spread оператора (*.). І тепер коду стало ще менше:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def names = persons*.firstName&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Відмінністю від collect є не тільки простота написання, але і краща швидкодія.&lt;br /&gt;&lt;br /&gt;І ось, в процесі написанні цієї статті, я відкрив для себе ще один спосіб. Коли починав писати цю статтю кілька хвилин тому, я вже не вірив, що може бути щось простіше, ніж використання spread оператора для вирішення моєї задачі. Але як виявилося, для отримання значення полів, використовувати spread оператор не є необхідним, і можна написати банально і просто:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def names = persons.firstName&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Тож сиджу і думаю, а як можна ще простіше. Боюся зарікатися, що простіше вже бути не може, як вже зрозумів свою помилку кілька хвилин тому.&lt;br /&gt;&lt;br /&gt;Groovy цікава мова, з якою все простіше і веселіше. Тож копати в Groovy, Python чи Ruby!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6249853213871895871?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6249853213871895871/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6249853213871895871' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6249853213871895871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6249853213871895871'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/11/groovy.html' title='Neverending Groovy'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5643944352270214438</id><published>2010-09-05T00:27:00.009+03:00</published><updated>2010-09-13T00:09:24.105+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'>Book Review: 97 Things Every Software Architect Should Know</title><content type='html'>More then year ago I bought book &lt;a href="http://www.amazon.com/Things-Every-Software-Architect-Should/dp/059652269X/ref=sr_1_fkmr0_3?ie=UTF8&amp;qid=1284320468&amp;sr=8-3-fkmr0"&gt;97 Things Every Software Architect Should Know&lt;/a&gt; for myself. I was expecting to get a book with some useful technical advices how to create cool software architecture,- that's what was always interesting for me. &lt;br /&gt;&lt;br /&gt;Instead I've got the book with 97 small articles, each 2 pages long. No technical advices, no silver bullet, no advices on what and how use design patterns or modern technologies. Truly say, after reading few articles, I was upset. And leaved the book on my bookshelf and move on. &lt;br /&gt;&lt;br /&gt;A year later, ie a month ago, I've took this book into my hands and decided that it's time to try to read it again. (Yes, I have a habit to re-read books again a year or two later, as found that it helps to understand much more and see the forest behind the trees).&lt;br /&gt;&lt;br /&gt;I'm still reading this - few articles per week,- but decided to note my thoughts as review in this article.&lt;br /&gt;&lt;br /&gt;In this attempt, book is very interesting. A year later my vision was changed cardinally again and now, I think, I can understand what those guys mean when they were writing their posts. These all can be said simply in one sentence: &lt;br /&gt;&lt;b&gt;Software Architects are bridges between business needs, software needs, technical needs and team needs&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Especially interesting were next articles for me (remember, I'm still reading):&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Don't Put Your Resume Ahead of the Requirements&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It Is All About The Data&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Pattern Pathology&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If You Design It, You Should Be Able to Code It&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Empower Developers&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Chances Are, You Biggest Problem Isn't Technical&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Business Drives&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Great Content Creates Great Systems&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Start with a Walking Skeleton&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Communication Is King; Clarity and Leadership, Its Humble Servants&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;I'm sure articles' titles are saying enough, so will not describe them. Want know more - just go and buy (as I did :)&lt;br /&gt;&lt;br /&gt;A week ago I was reading "Business Drives" article. And especially remembered the summary of this article: "The long-term interests of the software development team are best served when business drives". And I agree with this summary. It's sad to know, that many software developers are still in the race for better skills and modern technologies if this is in damage for the project and business. &lt;br /&gt;&lt;br /&gt;It's one of that books, that reminds that software is making by humans for humans.&lt;br /&gt;&lt;br /&gt;So, my advise is to get and read this book; hope you're ready for it and hope I'm too :)&lt;br /&gt;&lt;br /&gt;PS: Just found another review of this book &lt;a href="http://dotnet.dzone.com/news/97-things-every-software"&gt;http://dotnet.dzone.com/news/97-things-every-software&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5643944352270214438?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5643944352270214438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5643944352270214438' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5643944352270214438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5643944352270214438'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/09/book-review-97-things-every-software.html' title='Book Review: 97 Things Every Software Architect Should Know'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5216950694404695914</id><published>2010-09-04T23:19:00.020+03:00</published><updated>2010-09-06T22:15:59.793+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy annotations</title><content type='html'>As I wrote in my &lt;a href="http://java-ua.blogspot.com/2010/08/waiting-groovy-18.html"&gt;last post&lt;/a&gt; Groovy 1.8 is still in progress. One of the new features I liked a lot is annotation support for AST transformations (i.e. &lt;code&gt;@ToString, @Canonical&lt;/code&gt; etc.).&lt;br /&gt;&lt;br /&gt;As I'm still acquainted with Groovy, I've decided to look what useful annotations it has already. So this post is about what was found. &lt;br /&gt;&lt;br /&gt;There are next annotations in the &lt;code&gt;groovy.lang&lt;/code&gt; package:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;@Lazy&lt;/li&gt;&lt;li&gt;@Immutable&lt;/li&gt;&lt;li&gt;@Newify&lt;/li&gt;&lt;li&gt;@Singleton&lt;/li&gt;&lt;li&gt;@Mixin&lt;/li&gt;&lt;li&gt;@Category&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Also want to describe them with few simple samples.&lt;br /&gt;&lt;h4&gt;@Lazy&lt;/h4&gt;This annotation can be applied to class field. As result new instance for field value is created on &lt;code&gt;get&lt;/code&gt; method call for field property. In this case Groovy generates getter method for you, that checks whether field is not initialized yet and initialize it in this case, otherwise returns its value:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@Lazy T x&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;generates next code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private T $x&lt;br /&gt;&lt;br /&gt;T getX() {&lt;br /&gt;   if ($x != null)&lt;br /&gt;      return $x&lt;br /&gt;   else {&lt;br /&gt;      $x = new T()&lt;br /&gt;      return $x&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You also can do lazy field initialization with specified value, just assign this value for field with @Lazy annotation:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@Lazy T x = new T(code: 'S')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That will generate next code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private T $x&lt;br /&gt;&lt;br /&gt;T getX() {&lt;br /&gt;   T $x_local = $x&lt;br /&gt;   if ($x_local != null)&lt;br /&gt;      return $x_local&lt;br /&gt;   else {&lt;br /&gt;      synchronized(this) {&lt;br /&gt;         if ($x == null) {&lt;br /&gt;            $x = new T(code: 'S')&lt;br /&gt;         }&lt;br /&gt;         return $x&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Absolutely useful thing with only a few of keypresses. That's awesome.&lt;br /&gt;&lt;br /&gt;Read more in &lt;a href="http://groovy.codehaus.org/api/groovy/lang/Lazy.html"&gt;GroovyDoc&lt;/a&gt;&lt;br /&gt;&lt;h4&gt;@Immutable&lt;/h4&gt;Used to mark classes and make them immutable. That's mean that your class becomes final and nobody can change value field value and you get tuple and map based constructors. Also Groovy generated &lt;code&gt;toString(), hashCode()&lt;/code&gt; and &lt;code&gt;equals()&lt;/code&gt; methods for you. You should also need to be sure that fields types are immutable, primitives, strings, enums or are annotated with &lt;code&gt;@Immutable&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Read more in &lt;a href="http://groovy.codehaus.org/api/groovy/lang/Newify.html"&gt;GroovyDoc&lt;/a&gt;&lt;br /&gt;&lt;h4&gt;@Newify&lt;/h4&gt;This annotation is perfect for DSL expressions. With it you can change creating new objects expression, for example, use&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def b = Book('The Best Book Ever')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;instead of&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def b = new Book('The Best Book Ever')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Read more in &lt;a href="http://groovy.codehaus.org/api/groovy/lang/Immutable.html"&gt;GroovyDoc&lt;/a&gt;&lt;br /&gt;&lt;h4&gt;@Singleton&lt;/h4&gt;Well, another annotation that makes your life easier. As you maybe already understand, this annotation is for types and make them singletons. &lt;br /&gt;&lt;code&gt;getInstance()&lt;/code&gt; method is generated for you, so simply call it when you need new instance. If you set annotation &lt;code&gt;lazy&lt;/code&gt; parameter to be true, your singleton instance will be created on first call to this method. As for this case method supports double checking locks, you may be sure that only one instance will be created. Here is some sample:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@Singleton&lt;br /&gt;class Player {&lt;br /&gt;    def play() {}&lt;br /&gt;    def stop() {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Player.instance.start()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Read more in &lt;a href="http://groovy.codehaus.org/api/groovy/lang/Singleton.html"&gt;GroovyDoc&lt;/a&gt;  and &lt;a href="http://groovy.codehaus.org/Singleton+transformation"&gt;Singleton transformation&lt;/a&gt;.&lt;br /&gt;&lt;h4&gt;@Mixin&lt;/h4&gt;Used to mix one or few types into annotated type. As result, you can have a class that have members (fields and methods) from other classes, specified in the annotation. And here is sample:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Book {&lt;br /&gt;   String name&lt;br /&gt;   String author&lt;br /&gt;&lt;br /&gt;   def find(text) {&lt;br /&gt;      ....&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Mixing(Book)&lt;br /&gt;class HardBookMetadata extends Metadata {&lt;br /&gt;   int pages&lt;br /&gt;   String publication&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;....&lt;br /&gt;def metadata = new HardBookMetadata()&lt;br /&gt;metadata.title = 'Some cool title'&lt;br /&gt;metadata.author = 'Ruslan Khmelyuk'&lt;br /&gt;metadata.pages = 400&lt;br /&gt;&lt;br /&gt;println metadata.find('cool')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you see, using variable &lt;code&gt;metadata&lt;/code&gt; of &lt;code&gt;HardBookMetadata&lt;/code&gt; type have access to &lt;code&gt;Book&lt;/code&gt; members.&lt;br /&gt;Yeah, this also can be used with &lt;a href="http://groovy.codehaus.org/api/groovy/lang/Category.html"&gt;@Category&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Read more in &lt;a href="http://groovy.codehaus.org/api/groovy/lang/Mixin.html"&gt;GroovyDoc&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5216950694404695914?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5216950694404695914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5216950694404695914' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5216950694404695914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5216950694404695914'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/09/groovy-annotations.html' title='Groovy annotations'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-3393754835761998313</id><published>2010-08-31T21:18:00.007+03:00</published><updated>2010-09-04T23:27:44.665+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Waiting for Groovy 1.8</title><content type='html'>&lt;a href="http://groovy.codehaus.com"&gt;Groovy 1.8&lt;/a&gt; is going to be released in December 2010. First beta release is already open to download and second beta release will be ready in September.&lt;br /&gt;&lt;br /&gt;Groovy developers team preparing for us a few important surprises. &lt;br /&gt;&lt;br /&gt;They added more AST transformations, for different cases like &lt;code&gt;@Canonical, @EqualAndHashCash, @ToString&lt;/code&gt; and many others. You may use such annotations to generate &lt;code&gt;toString(), equals(), hashCode()&lt;/code&gt; methods on compilation. @InheritConstructors helps to generate inherit all parent constructors, and here is &lt;a href="http://jira.codehaus.org/browse/GROOVY-3391"&gt;link to task&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Another interesting feature is &lt;a href="http://jira.codehaus.org/browse/GROOVY-4322"&gt;Closure composition&lt;/a&gt;, so now it's possible to use special syntax to compose multiple closures, like:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def log = { a -&gt; println(a); a }&lt;br /&gt;def save = { a -&gt; dao.save(a); a}&lt;br /&gt;def notify = { a -&gt; notificationService.notify(a); a }&lt;br /&gt;&lt;br /&gt;// so now instead of calling notify(save(log(user)))&lt;br /&gt;// you may call it like&lt;br /&gt;def action = log &gt;&gt; save &gt;&gt; notify&lt;br /&gt;action(user) &lt;br /&gt;&lt;br /&gt;// or even like&lt;br /&gt;notify &lt;&lt; save &lt;&lt; log &lt;&lt; user  // is that awesome or awful?!&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Also they prepared few performance improvements: avoiding calling methods when it's not necessary and processing operations on integers as primary type values but not objects (like, incrementing or adding). As result Groovy can be used for mathematical calculations without performance issues. &lt;a href="http://wiki.jvmlangsummit.com/images/0/04/Theodorou-Faster-Groovy-1.8.pdf"&gt;In this presentation&lt;/a&gt; you can read much more about this. And &lt;a href="http://jira.codehaus.org/browse/GROOVY-3951"&gt;here are related jira tasks&lt;/a&gt; so anyone can watch the progress.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jira.codehaus.org/browse/GROOVY-3991"&gt;This issue&lt;/a&gt; is fixed so they can't say that "Ruby is right, Groovy is wrong" anymore :)&lt;br /&gt;&lt;br /&gt;Annotations now can accept closure as argument:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;@Validator { password.size() &gt; 6 }&lt;br /&gt;String password&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;This &lt;a href="http://jira.codehaus.org/browse/GROOVY-3093"&gt;task&lt;/a&gt; contains more information and links.&lt;br /&gt;&lt;br /&gt;Closure currying is a powerful thing. And now it's possible to curry right and 2nd (of three) parameter. Moreover no need to wait Groovy 1.8 to try this, because it's available right now and right here, starting from version 1.7.2 of course ;)&lt;br /&gt;&lt;br /&gt;Well, that's all about this for now. Waiting for Groovy 1.8 and for more interesting things to be released this December.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-3393754835761998313?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/3393754835761998313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=3393754835761998313' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3393754835761998313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3393754835761998313'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/08/waiting-groovy-18.html' title='Waiting for Groovy 1.8'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4372992392697511095</id><published>2010-08-28T09:33:00.009+03:00</published><updated>2010-09-03T00:13:11.916+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='webservice'/><category scheme='http://www.blogger.com/atom/ns#' term='spring ws'/><category scheme='http://www.blogger.com/atom/ns#' term='jaxb'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>SpringWS and Jaxb</title><content type='html'>Well, truly say this small post is not about &lt;i&gt;how to use&lt;/i&gt; &lt;a href="http://static.springsource.org/spring-ws/sites/1.5/"&gt;SpringWS&lt;/a&gt; and &lt;a href="https://jaxb.dev.java.net/"&gt;Jaxb&lt;/a&gt; together. It's more about potential power of this combination. I know, that combination is in release for few years alredy and used by thousands of developers. But this article is more for guys in doubt if they really need SpringWS rather than for experienced Spring WS developers.&lt;br /&gt;&lt;br /&gt;First of all, I want to say that Spring WS is very powerful framework. I've noticed it when version 1.0 beta was released. As everything in Spring it has good API, simple implementation model and as result it was very flexible. And this mean that you can easily introduce need changes and extensions without changing Spring WS source code.&lt;br /&gt;&lt;br /&gt;From the beginning, the Spring WS team was saying that SpringWS should support not only low-level request processing, when you have some object that represents input XML document or build output XML document, but can use different mapping and translation libraries to make it for you. And here is a place for Jaxb.&lt;br /&gt;&lt;br /&gt;To enable marshaling you need just to do few simple changes:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; Add &lt;code&gt;marshaller&lt;/code&gt; bean of &lt;code&gt;org.springframework.oxm.jaxb.Jaxb2Marshaller&lt;/code&gt; type:&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"&amp;gt;&lt;br /&gt;    &amp;lt;property name="classesToBeBound"&amp;gt;&lt;br /&gt;        &amp;lt;list&amp;gt;&lt;br /&gt;            &amp;lt;value&gt;GetImageRequest&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;value&gt;GetImageResponse&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;value&gt;AddImageRequest&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;value&gt;AddImageResponse&amp;lt;/value&amp;gt;&lt;br /&gt;        &amp;lt;/list&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;li&gt; Add Marshaling Method Endpoint Adapter to yours spring.xml:&lt;br /&gt;&lt;pre&gt;&amp;lt;bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter"&amp;gt;&lt;br /&gt;     &amp;lt;property name="marshaller" ref="marshaller"/&amp;gt;&lt;br /&gt;     &amp;lt;property name="unmarshaller" ref="marshaller"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;li&gt; Well, that's all :)&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;And then, after some testing, I found that it would be nice to trim input text fields and do other post-marshalling operations. And I was sure there was a &lt;b&gt;normal&lt;/b&gt; way to do that with rather Spring WS or Jaxb. After a few minutes of searching, I have found the way and had completely working code that was doing what I was needed. &lt;br /&gt;&lt;br /&gt;The catch is that Jaxb &lt;code&gt;Unmarshaller&lt;/code&gt; supports listeners and Spring's &lt;code&gt;Jaxb2Marshaller&lt;/code&gt; has a property &lt;code&gt;unmarshallerListener&lt;/code&gt;, that points your listener to &lt;code&gt;Unmarshaller&lt;/code&gt;'s listeners. &lt;br /&gt;With only 3 lines of configuration we have own listener called on each unmarshalling:&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"&gt;&lt;br /&gt;   ....&lt;br /&gt;   &amp;lt;property name="unmarshallerListener"&gt;&lt;br /&gt;       &amp;lt;bean class="TargetHandlerUnmarshallerListener"/&gt;&lt;br /&gt;   &amp;lt;/property&gt;&lt;br /&gt;&amp;lt;/bean&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here is &lt;code&gt;TargetHandlerUnmarshallerListener&lt;/code&gt; code:&lt;br /&gt;&lt;pre&gt;import javax.xml.bind.Unmarshaller;&lt;br /&gt;&lt;br /&gt;public class TargetHandlerUnmarshallerListener extends Unmarshaller.Listener {&lt;br /&gt;&lt;br /&gt;    @Override public void afterUnmarshal(Object target, Object parent) {&lt;br /&gt;        super.afterUnmarshal(target, parent);&lt;br /&gt;&lt;br /&gt;        if (target instanceof PostPopulatedHandler) {&lt;br /&gt;            ((PostPopulatedHandler) target).postPopulated();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;In this class I override only &lt;code&gt;afterUnmarshal()&lt;/code&gt; method, that is called after XML is transformed to the Java object. You can also override &lt;code&gt;beforeUnmarshal()&lt;/code&gt; method if you need.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;PostPopulatedHandler&lt;/code&gt; is my own interface that expose only &lt;code&gt;postPopulated()&lt;/code&gt; method. Each class knows what to do after unmarshalling, and declares it in the &lt;code&gt;postPopulated()&lt;/code&gt; method. Of course, there can be used some annotation, but interface option is the most simple, easier and obvious way.&lt;br /&gt;&lt;br /&gt;So, some summary is next: Spring libraries are awesome, because they always provide very good API and you always can do what you need without changing library source code. Jaxb is awesome as well. I'm noticing this, because &lt;i&gt;it's always hard to write good API&lt;/i&gt;, especially in multifunctional libraries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4372992392697511095?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4372992392697511095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4372992392697511095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4372992392697511095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4372992392697511095'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/08/springws-and-jaxb.html' title='SpringWS and Jaxb'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-972177183948161789</id><published>2010-08-28T01:04:00.011+03:00</published><updated>2010-08-31T23:35:14.217+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Migrate from SVN repository to Git</title><content type='html'>As I was saying in my &lt;a href="http://java-ua.blogspot.com/2010/08/git-and-github.html"&gt;previous post&lt;/a&gt; it is easy to migrate you project from Subversion to Git.&lt;br /&gt;&lt;br /&gt;Really, you will need just a few commands to run.&lt;br /&gt;&lt;br /&gt;First of all you need to make a clone of Subversion repository using &lt;a href='http://www.kernel.org/pub/software/scm/git/docs/git-svn.html'&gt;git-svn&lt;/a&gt; tool:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ git svn clone --authors-file=authors.txt https://example/svn/MyRepo/trunk/project project&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;On this command git will go through the history of the project and fetch it into local git repository. If your subversion repository is using standard layout (i.e. trunk, branches and tags paths are present in the SVN repository root tree) than you may be interesting in &lt;code&gt;--stdlayout&lt;/code&gt; option. You may also specify custom path for trunk or branches or tags using &lt;code&gt;-T&lt;/code&gt; or &lt;code&gt;-t&lt;/code&gt; or &lt;code&gt;-b&lt;/code&gt; option respectively.&lt;br /&gt;&lt;br /&gt;Option &lt;code&gt;--authors-file&lt;/code&gt; contains the path to the file with committers mapping.&lt;br /&gt;This file contains SVN committer mapping to git user per line.&lt;br /&gt;For example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ruslan = Ruslan &amp;lt;ruslan@example.com&amp;gt;&lt;br /&gt;john = John Smith &amp;lt;john@smith.com&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;So now you have local working copy that is managed by Git and also you have all project history in your local repository. It's easy to check what branches and tags you have using next commands:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ cd project&lt;br /&gt;$ git branches&lt;br /&gt;$ git tag -l&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;If you have remote Git repository (maybe in GitHub), than you may want to push source code with all history to that repository. And it is not a problem, as you have already everything you need.&lt;br /&gt;&lt;br /&gt;1. So add remote repository:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ git remote add origin git@github.com:myname/myproject.git    &lt;br /&gt;&lt;/code&gt;&lt;br /&gt;2. And push to the remote repository:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ git push origin master&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;3. and be happy - now you have migrated to the git repository. &lt;br /&gt;&lt;br /&gt;Remove directory with SVN repository clone and make another clone but from git repository and continue using it:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ cd ..&lt;br /&gt;$ rm -rf project&lt;br /&gt;$ mkdir project&lt;br /&gt;$ cd project&lt;br /&gt;$ git init&lt;br /&gt;$ git remote add origin git@github.com:myname/myproject.git   &lt;br /&gt;$ git pull origin master&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Thats how it worked for me 2 months ago.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-972177183948161789?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/972177183948161789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=972177183948161789' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/972177183948161789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/972177183948161789'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/08/migrate-from-svn-repository-to-git.html' title='Migrate from SVN repository to Git'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4925380236228956936</id><published>2010-08-25T22:46:00.007+03:00</published><updated>2010-08-26T23:41:37.324+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><title type='text'>Git and GitHub</title><content type='html'>Completely moved to &lt;a href="http://git-scm.org"&gt;Git&lt;/a&gt; and it's awesome. Feeling like someone unleashed my hands. Git works much faster than Subversion in everyday use. Using branches is easy and &lt;b&gt;NORMAL&lt;/b&gt; and I'm using it day by day. No more need to have many directories with strange names and different project versions. No more fear before merging. No more failures on merging.&lt;br /&gt;&lt;br /&gt;My opinion is that everyone must try and use some of distributed version control system, like &lt;a href="http://git-scm.org"&gt;Git&lt;/a&gt; or &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt; or &lt;a href="http://bazaar.canonical.com/en/"&gt;Bazaar&lt;/a&gt;. I've started using Git intensively with projects under Subversion. It was possible thanks to the &lt;a href='http://www.kernel.org/pub/software/scm/git/docs/git-svn.html'&gt;git-svn&lt;/a&gt; project and I was working on Windows in that times. Now I'm on Linux and using git is much easier and natural. git-svn also is very useful to migrate projects from svn repository to the git repository. On checking out project you need to wait some time, because it reads the all history of repository with all changes, that is pretty long in subversion for large projects. As soon you have clone of the project svn repository, you push your changes to central git repository if any. If you need you can do commiters mapping. If you need, you can continue work with both repositories.&lt;br /&gt;&lt;br /&gt;And what about &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;? It's another awesome software. A lot of open source projects are using GitHub. You easily can have and use private repositories and it's pretty cheap - only $7 per month for 5 private repositories. &lt;br /&gt;Each repository goes with wiki, basic issues tracker, useful reports and many others. Especially, I like Network graph, because it helps to visualize commits and merge history.&lt;br /&gt;&lt;br /&gt;Some interesting links:&lt;br /&gt;1. &lt;a href="http://progit.com"&gt;ProGit online book&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.viget.com/extend/effectively-using-git-with-subversion/"&gt;Git with Subversion&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.gitcasts.com/"&gt;GitCasts&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.infoq.com/interviews/erlang-and-github"&gt;The way GitHub helped Erlang and the way Erlang helped Github&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Other related posts:&lt;br /&gt;1. &lt;a href="http://java-ua.blogspot.com/2009/04/git-and-subversion-works-together.html"&gt;Git and Subversion work together&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4925380236228956936?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4925380236228956936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4925380236228956936' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4925380236228956936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4925380236228956936'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/08/git-and-github.html' title='Git and GitHub'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6858223254640950351</id><published>2010-08-25T22:14:00.007+03:00</published><updated>2010-08-25T22:46:43.741+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Ruslan and Linux</title><content type='html'>Давненько я нічого не писав...&lt;br /&gt; &lt;br /&gt;За такий здавалося нетривалий період часу, багато чого встигло помінятися, тому, думаю, буде що розсказати.&lt;br /&gt;&lt;br /&gt;Мабуть, найбільшою зміною для мене був цілковитий перехід на Linux. Ось уже від початку травня я є гордим користувачем &lt;a href="http://ubuntu.com"&gt;Ubuntu 10.04&lt;/a&gt;. Перехід видався значно простішим, ніж можна було очікувати, але це скоріше за все результат моїх попередніх поривань в цю сторону, а також нетривалого, але плідного використання &lt;a href="http://slackware.com"&gt;Slackware&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Важко далося використання MS SQL Server на локальній машині під Linux. Не можу сказати як я вирішив цю проблемо, тому що я її не вирішив. Використовувати віртуальну машину було нереально, адже в результаті тормозило все і вся. Тому довелося використовувати віддалений сервер і в результаті працювати тільки в онлайн. Благо, тепер потреба в ньому мінімальна.&lt;br /&gt;&lt;br /&gt;Декілька слів про Ubuntu. Зручно, приємно, вражаюче і крім цього є консоль із всіма її потугами. Через кілька тижнів використання, я вже не міг собі уявити себе без Linux, а Windows 7 почав виглядати поцікавому і, навіть можна сказати, екзотично. &lt;br /&gt;А ще недавнo я для себе відкрив, що в mc можна використовувати мишку. І це могло би перевернути мій світ, але не стало ;)&lt;br /&gt;&lt;br /&gt;Люблю консоль. Консоль та набір скриптів дозволили оптимізувати роботу в Linux та роботу по проектах.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6858223254640950351?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6858223254640950351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6858223254640950351' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6858223254640950351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6858223254640950351'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/08/ruslan-and-linux.html' title='Ruslan and Linux'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1615195197137237549</id><published>2010-03-24T21:48:00.004+02:00</published><updated>2010-03-24T21:54:41.194+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ffmpeg'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Screen cast on linux with ffmpeg</title><content type='html'>Few days ago I was happy to found the link with 10 useful Linux commands at &lt;a href="http://www.catonmat.net/blog/top-ten-one-liners-from-commandlinefu-explained/"&gt;http://www.catonmat.net/blog/top-ten-one-liners-from-commandlinefu-explained/&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;The last one command was the most interesting for me, as it helps to make screen casts quickly and easy with only one command:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ffmpeg -f x11grab -s wxga -r 25 -i :0.0 -sameq ~/out.mpg&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Moreover ffmpeg helps to setup video quality, convert it to FLV format, so you can publish video online with a few clicks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1615195197137237549?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1615195197137237549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1615195197137237549' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1615195197137237549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1615195197137237549'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/03/screen-cast-on-linux-with-ffmpeg.html' title='Screen cast on linux with ffmpeg'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-2853799403685000478</id><published>2010-03-14T12:13:00.001+02:00</published><updated>2010-03-14T12:17:47.728+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='comics'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><title type='text'>Dilber and co</title><content type='html'>&lt;a href="http://dilbert.com/strips/comic/2010-03-14/" title="Dilbert.com"&gt;&lt;img src="http://dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/80000/4000/500/84511/84511.strip.sunday.gif" border="0" alt="Dilbert.com" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-2853799403685000478?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/2853799403685000478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=2853799403685000478' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2853799403685000478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2853799403685000478'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/03/dilbertcom.html' title='Dilber and co'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-953643765637423685</id><published>2010-02-01T20:16:00.006+02:00</published><updated>2010-02-01T20:28:23.973+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'>Beautiful Code</title><content type='html'>&lt;table&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding-right:10px;"&gt;&lt;img src="http://www.ozon.ru/multimedia/books_covers/1000974156.jpg"/&gt;&lt;/td&gt;&lt;td&gt;Зовсім недавно повернувся зі Львова. Купив собі в &lt;a href="http://hyade.com/"&gt;Гіаді&lt;/a&gt; декілька цікавих книжок. Серед них і &lt;a href="http://www.ozon.ru/context/detail/id/4187085/"&gt;Beautiful Code&lt;/a&gt;. Тільки от почав її читати.&lt;br /&gt; &lt;br /&gt;В книзі міститься 33 історії від відомих програмістів, в яких вони діляться враженням від певного коду чи технології. Кожна історія проникнена поглядами і думками на цікаві речі, що розглядаються з призми красивого коду. Інколи код не зовсім-то й красивий на перший погляд, і автори намагаються відкрити ту красу, що побачили вони.&lt;br /&gt;&lt;br /&gt;А ще автори не відчувають жодних рамок у виборі красивого коду, і в книзі можна зустріти C, C++, Perl, Java, Python.&lt;br /&gt;&lt;br /&gt;Так що раджу почитати.&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-953643765637423685?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/953643765637423685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=953643765637423685' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/953643765637423685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/953643765637423685'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2010/02/beautiful-code.html' title='Beautiful Code'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6747184684611123981</id><published>2009-12-09T20:42:00.003+02:00</published><updated>2009-12-09T20:59:35.108+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='News'/><category scheme='http://www.blogger.com/atom/ns#' term='Intellij Idea'/><title type='text'>Реліз IntellijIDEA 9.0 (Maia)</title><content type='html'>Нарешті відбувся реліз &lt;a href="http://www.jetbrains.com/idea/index.html"&gt;IntellijIDEA 9.0&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Для мене це було неочікувано, хоча користуюся EAP'ами вже давно. Перейшов через підтримку FreeMarker та Velocity. А пізніше добавилась перевірка коректності слів по словнику, відчутно покращилася швидкодія в останніх EAP версіях, можливість назначати кольори окремим групам файлів, потім добавилося code folding для дженериків та анонімних класів та багато іншого. Цікаво також, що є можливість генерити діаграми класів, діаграми змінених класів, підключення до Jira та YouTrack для роботи із тасками.&lt;br /&gt;&lt;br /&gt;Версія 9.0 вийшла в двох редакція: повнофункціональна Ultimate Edition з підтримкою JavaEE та великої кількості плагінів, а також безкоштовної з відкритим кодом Community Edition.&lt;br /&gt;&lt;br /&gt;Корисні посилання:&lt;br /&gt;1. &lt;a href="http://blogs.jetbrains.com/idea/"&gt;IntellijIDEA blog&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.jetbrains.com/idea/whatsnew/index.html"&gt;IDEA what's new&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6747184684611123981?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6747184684611123981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6747184684611123981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6747184684611123981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6747184684611123981'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/12/intellijidea-90-maia.html' title='Реліз IntellijIDEA 9.0 (Maia)'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-807094646036718651</id><published>2009-12-08T00:49:00.005+02:00</published><updated>2009-12-08T01:24:11.031+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uml'/><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'></title><content type='html'>Задумався я над UML. Вчу студентів, що це дуже корисна річ, часто використовується в реальному світі. Допомогає не тільки спроектувати програму, але і донести свою думку до інших, зрозуміти чужу програму; є важливою частина документації.&lt;br /&gt;&lt;br /&gt;І справді, UML буває корисним для того, щоб спроектувати програму, якщо це взагалі можливо зробити в повній мірі. Донести думку до інших за допомогою UML - річ також нетривіальна, хоча все залежить. Щодо технічної документації, то я прихильник думки, що найкраща документація - це сам код програми (доречі &lt;a href="http://gaperton.livejournal.com/32772.html"&gt;тут&lt;/a&gt; можна почитати про це більше).&lt;br /&gt;&lt;br /&gt;А ще часто доводиться чути думки, що UML - це зайве, що все в голові можна спроектувати, і при цьому особливо "ясно видно динаміку". Інші не розуміють, навіщо ці квадратики та кружочки; a це й чоловічок (которий актор, чи то пак актант) взагалі смішно виглядає. Інші і не знають про це або знають, але не пробували.&lt;br /&gt;&lt;br /&gt;Кожному своє. Я ж використовую UML, точніше ту частину, що мені справді допомагає. Я не пробую спроектувати всю систему, бо зазвичай це є неможливо через складність, величину системи чи плинність вимог. І звичайно я не завжди використовую UML, тільки коли це потрібно.&lt;br /&gt;&lt;br /&gt;Натомість при розробці певної функції програми, що виходить поза межі стандартних шаблонів та правил проекту не можу обійтися без діаграм випадків використання, класів та послідовностей. Цих трьох діаграм для мене достатньо.&lt;br /&gt;&lt;br /&gt;Спершу визначити список випадків використання та їх сценарії, як результат визначити список додаткових питань та білих плям в специфікації. Після цього вже на основі прецендентів паралельно будуються діаграми класів та послідовностей. Роблю це все на листочку або на боарді. Зазвичай, починаю з основного і закінчую другорядними класами та зв'язками. Найцікавіше потім переробити систему, починаючи з найпростіших другорядних класів та закінчуючи основними. Наступне просіювання починається при написанні коду. Знову ж таки, писати починаю з найпростіших і/або другорядних класів. Це не тільки дає час подумати над удосконаленням основних класів та інтерфейсів, а також прощупати це все ручками в коді, визначити білі плями, розбіжності та несходження.&lt;br /&gt;&lt;br /&gt;Ось так вона, думка, спочатку матеріалізується на бумазі, відточується, потім перетворюється в код, і ще раз відточується. &lt;br /&gt;&lt;br /&gt;І взагалі, дуже цікаву книжку Крега Лармана &lt;a href="http://www.ozon.ru/context/detail/id/3105480/"&gt;Применение UML 2.0 и шаблонов проектирования&lt;/a&gt;. Якщо є перша версія, то можна почитати її, як це колись зробив я. Раджу всім, особливо студентам, що хочуть зрозуміти принципи проектування та розробки ОО програмного забезпечення.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-807094646036718651?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/807094646036718651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=807094646036718651' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/807094646036718651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/807094646036718651'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/12/uml.html' title=''/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-2675253644620388081</id><published>2009-12-07T00:25:00.006+02:00</published><updated>2009-12-07T01:33:11.269+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JMeter'/><category scheme='http://www.blogger.com/atom/ns#' term='Apache'/><title type='text'>Apache JMeter</title><content type='html'>Попрацював сьогодні трохи з &lt;a href="http://jakarta.apache.org/jmeter/"&gt;JMeter&lt;/a&gt;. Давно знаю про цю програму, давно хотів навчитися її використовувати, але до сьогодні якось не складалося.&lt;br /&gt;&lt;br /&gt;Загальне враження від неї позитивне: простий інтерфейс, зручне представлення тесту у вигляді дерева, чітко визначений життєвий цикл тесту та послідовність виконання кожного елементу тесту дозволяют швидко накидати та запустити тест. А набір лістенерів дозволяють представити отримані дані зберегти та представити у зручному вигляді: таблиці із детальними та середніми значеннями, графіки тощо.&lt;br /&gt;&lt;br /&gt;Звичайно необовязково запускати JMeter у візуальному режимі. Можна також скористатися режимом командного рядка або сервера для розприділеного тестування. Включивши навантажувальні тести JMeter в процес збірки певних версії проекту (наприклад, тестових версій, чи спеціальних щотижневих версій), можна контролювати метрику швидкодії програми. І все це безкоштовно. &lt;br /&gt;&lt;br /&gt;Сьогодні використовувати її проте прийшлося тільки для перевірки середньої швидкодії програми при різних навантаженнях на різних серверів. Висновок: трохи треба попрацювати над швидкодією окремих речей. А ще планую підготувати декілька простих тестових випадків і періодично знімати метрики зміни швидкодії та масштабування в процесі розробки.&lt;br /&gt;&lt;br /&gt;Особливо цікаво також було порівняти зібраних даних з серверів та мого ноутбука. Висновок: настав час придбати собі нового звіра :).&lt;br /&gt;&lt;br /&gt;Корисні посилання:&lt;br /&gt;1. &lt;a href="http://jakarta.apache.org/jmeter/usermanual/"&gt;JMeter User Manual&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.scribd.com/doc/7499267/Load-Testing-With-JMeter"&gt;http://www.scribd.com/doc/7499267/Load-Testing-With-JMeter&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.javaworld.com/javaworld/jw-07-2005/jw-0711-jmeter.html"&gt;JMeter tips&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-2675253644620388081?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/2675253644620388081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=2675253644620388081' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2675253644620388081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2675253644620388081'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/12/apache-jmeter.html' title='Apache JMeter'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7243637573814123985</id><published>2009-11-03T23:41:00.005+02:00</published><updated>2009-11-04T00:08:23.281+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freemarker'/><title type='text'>Freemarker Tips</title><content type='html'>I like FreeMarker. It's simple, functional and pretty fast tool.&lt;br /&gt;In project we are using Freemaker with SpringMVC. &lt;br /&gt;&lt;br /&gt;To work with message bundle are used few macros, one of them is &lt;code&gt;spring.messageArgs&lt;/code&gt;. So today I've spent some time on searching how to pass argument to it. There was only one argument and, obviously, I was expecting that this macros could be used in next way:&lt;br /&gt;&lt;pre&gt;&amp;lt@spring.messageArgs "some.message.key" "argumentValue"/&amp;gt;&lt;/pre&gt;&lt;br /&gt;Unfortunately it's not so easy :(. The macros is calling method that accepts arguments as an array of objects. And string &lt;code&gt;"argumentValue"&lt;/code&gt; isn't an array. So I found next simple solution:&lt;br /&gt;&lt;pre&gt;&lt;#assign args = ["Ruslan"]/&gt;&lt;br /&gt;&amp;lt@spring.messageArgs "hello.man" args/&amp;gt;&lt;/pre&gt;&lt;br /&gt;where&lt;br /&gt;&lt;pre&gt;hello.man = Hello {0}!&lt;/pre&gt;&lt;br /&gt;Another interesting thing about Freemarker is the way you can print numbers. If you want to print  number value in argument X as a regular number rather than formatted number, you may do it in next way ${X?c}. I always forget to add ?c suffix and later receive many errors. Fortunately, it's possible to use #{X} that has the same effect. I found that it saves my time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7243637573814123985?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7243637573814123985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7243637573814123985' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7243637573814123985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7243637573814123985'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/11/freemarker-tips.html' title='Freemarker Tips'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5439625448614439720</id><published>2009-09-13T12:10:00.002+03:00</published><updated>2009-09-13T12:13:20.690+03:00</updated><title type='text'></title><content type='html'>Вітаю всіх програмістів з Днем програміста :)&lt;br /&gt;&lt;br /&gt;Думайте - пишіть, ще раз подумайте і (пере)пишіть.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5439625448614439720?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5439625448614439720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5439625448614439720' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5439625448614439720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5439625448614439720'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/09/blog-post.html' title=''/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6782120314957746024</id><published>2009-08-31T02:49:00.004+03:00</published><updated>2009-08-31T02:56:54.698+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Code Generation at Java</title><content type='html'>Some time ago I found how the code generation techniques are used at Java.&lt;br /&gt;Java NIO exposes a set of Buffer interfaces with package level implementations that are returned while creating buffers. If you will look at those implementation classes (HeapByteBuffer or DirectByteBuffer) you will notice that they are generated. Look at the file header comments - and you will see notion that it's generated and the name of the template. You may find templates with description of it's parameters &lt;a href="http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/io-nio/java.nio.htm"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6782120314957746024?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6782120314957746024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6782120314957746024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6782120314957746024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6782120314957746024'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/08/code-generation-at-java.html' title='Code Generation at Java'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6735921282581821027</id><published>2009-08-31T01:09:00.012+03:00</published><updated>2009-08-31T02:58:10.588+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='Freemarker'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Code Generation</title><content type='html'>We are writing the code and this is our job. That's the art that we make. We put our thoughts, our patient, our soul to make it ideal or near to ideal. Sometimes we just write the code asap as there is no time or code is simple or we wrote similar code hundreds of times. This small article is about writing similar code again and again.&lt;br /&gt;&lt;br /&gt;When we are writing similar code second or fourth time it's not an art and it is tedious. But that's useful to polish previous code: we can find and fix bugs, add needed logging, rewrite with better performance, make the code clean and handy to read and change etc. Often we are changing previously written code to make it better as well. &lt;br /&gt;But what if you need to write similar code tens or hundreds of times? Will you change previous 20 classes because now you find the best algorithm or fixed the annoying problem with performance? Will you be glad to fix 50 classes over the project because just now you find the bug? (so it must be fixed, right?)&lt;br /&gt;That will take your time, that you could spend on coding something interesting or studying some new popular technology or have a beer with your friends. And what about customer for whom this software is a business. &lt;br /&gt;That's why I'm writing about code generation, the thing we all know and use often. You remember, when you're creating new project or adding new class with your favorite IDE, you got initial code so you can write your important part rather that spend time on writing the same code again and again. &lt;br /&gt;While reviewing code generation tools we can divide them into external and internal. External are provided by IDE or other providers (remember famous xdoclet toolkit?). Internal is written by your team and used withing some one or few projects. &lt;br /&gt;Internal code generators could be simple enough to generate only basic template source code or UI that will be changed and extended. It also can be large and complex to generate layers (domain types, DAOs and repositories etc) of your software.&lt;br /&gt;&lt;br /&gt;Lets review next types of code generators:&lt;br /&gt; 1. template code generators&lt;br /&gt; 2. partial code generators&lt;br /&gt;&lt;br /&gt;Template code generators run once at the begin. They are responsible for generating source code that will be rewritten or extended by developer. It's important to have clean generated code with comments for generated code and for placements where to put your code. It's good to use such generators if you have already ideal code to be generated. Ideal means that you will not need ever to change template and regenerate the same code again and again. Regenerating code will remove code written by developers with hands.&lt;br /&gt;&lt;br /&gt;Partial code generators could be run as much as you will need. They are separated from code written by developers. For C# that would be good to use &lt;b&gt;partial&lt;/b&gt; keyword (as I remember partial class declaration was added to have distinct generated and written by developer code for WinForms and ASP.NET); for Java extending could be used as well. We use generator to generate only similar code and put in another file, e.g. partial class definition or base abstract class. The specific code is written in derived class. While we find new bugs and improvements we need just to change templates or generator configuration and regenerate the code again.&lt;br /&gt;&lt;br /&gt;Although code is generated it also must be easy to read it. Document your code, as you need to do it only once - in templates, so don't be lazy and stingy! For partial code generator or template code generator that is twice as important, as you are working directly with generated code.&lt;br /&gt;Don't forget to add comment with notion that code is generated automatically and can be regenerated again, so other developers will think twice before changing it by hands!&lt;br /&gt;&lt;br /&gt;Also remember that it's okay to add code generation to project step-by-step. For example, I'm the only who is using the new generator for now. I need to do so to find and fix defects, find the parts of code that could and must be generated, improve configuration and way of use. In this case the generated base code (with partial code generator) is commited too.&lt;br /&gt;&lt;br /&gt;Use the best tools to write templates. For example I'm using Freemarker template engine to describe templates and generate source code. There are few code generators that read configuration file and generate appropriate code. For such tools performance is not as important as flexibility of templates and configuration.&lt;br /&gt;&lt;br /&gt;Document the generator. Share source code within team. Put your generator into source code repository near to the project, but not into it. Also make and tag latest stable version as runnable scripts or program, so other developers can update and use it without spending on it additional time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6735921282581821027?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6735921282581821027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6735921282581821027' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6735921282581821027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6735921282581821027'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/08/code-generation.html' title='Code Generation'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7386989674433229458</id><published>2009-07-27T03:49:00.006+03:00</published><updated>2009-12-07T01:30:43.153+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Apache Commons'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Apache'/><title type='text'>ToStringBuilder and multi-thread environment</title><content type='html'>Just found some article about using Apache Commons' &lt;code&gt;ToStringBuilder&lt;/code&gt; tool and about what a wonderful tool it is. And I decided to write about it too.&lt;br /&gt;&lt;br /&gt;Well, there were few projects where I was able to use Apache Commons Lang tool called &lt;code&gt;ToStringBuilder&lt;/code&gt;. It's very useful tool that helps to print information about class instance in the &lt;code&gt;toString()&lt;/code&gt; method. I just was need to write&lt;br /&gt;&lt;pre code="java"&gt;&lt;br /&gt;@Override&lt;br /&gt;public String toString() {&lt;br /&gt;    return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)&lt;br /&gt;            .append("Id", id)&lt;br /&gt;            .append("Name", name)&lt;br /&gt;            .append("Description", description)&lt;br /&gt;            .toString();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and as result got a string with nice-look instance description. It was perfect for me. &lt;br /&gt;But now I'm not using this tool. And wasn't using it for the last 10 months as well. I would be happy to use it rather than own implementation over &lt;code&gt;StringBuilder&lt;/code&gt; but I can't. &lt;br /&gt;&lt;code&gt;ToStringBuilder&lt;/code&gt; has problems with running in multi-thread environment. If you have class &lt;code&gt;A&lt;/code&gt; that uses &lt;code&gt;ToStringBuilder&lt;/code&gt; and you're going to use instances of this class in different threads - &lt;b&gt;be careful&lt;/b&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7386989674433229458?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7386989674433229458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7386989674433229458' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7386989674433229458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7386989674433229458'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/07/tostringbuilder-and-multi-thread.html' title='ToStringBuilder and multi-thread environment'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-273008874781751574</id><published>2009-07-17T02:31:00.007+03:00</published><updated>2009-12-08T01:23:10.914+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'>Google Books</title><content type='html'>&lt;a href="http://translate.google.com/translate?hl=en&amp;sl=uk&amp;tl=en&amp;u=http://java-ua.blogspot.com/2009/07/google-books.html"&gt;English version by Google Translate&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Не секрет, що у світі Google Books відбуваються чималі зміни. &lt;br /&gt;Про це все &lt;a href="http://books.google.com/googlebooks/agreement/"&gt;розказує сам Google&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Сервіс дуже цікавий, і сподіваюся кількість повністю доступних та щойно виданих книхо з часом збільшиться. Адже є книжки, яких вже і не купиш, а є книжки - як хочеться купити або навіть потрібно купити, але змушений часто це робити без перегляду хоч якогось контенту. Гугл може дати можливість віртуального швидкого перегляду книжки перед купівлею, - наче ви в справжньому магазині.&lt;br /&gt;&lt;br /&gt;Подобається також можливість створювати власну бібліотеку. Або вставляти фрейв сторінку із книжкою :)&lt;br /&gt;&lt;br /&gt;&lt;iframe frameborder="0" scrolling="no" style="border:0px" src="http://books.google.com/books?id=1dx34EMVyi8C&amp;lpg=PP1&amp;dq=Core%20J2EE%20patterns&amp;as_brr=0&amp;hl=uk&amp;pg=PP1&amp;output=embed" width=600 height=700&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-273008874781751574?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/273008874781751574/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=273008874781751574' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/273008874781751574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/273008874781751574'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/07/google-books.html' title='Google Books'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7268316280927213413</id><published>2009-07-06T20:57:00.002+03:00</published><updated>2009-07-06T00:50:06.175+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven допоможе!</title><content type='html'>Вирішив записати декілька корисних речей, з якими доводиться мати часто справу користувачу мавена в повсякденному житті, наприклад, мені:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;Запуск із ключиком &lt;code&gt;-o&lt;/code&gt; каже мавену працювати в оффлайновому режимі, а це інколи економить час якого немає. В цьому випадку мавен шукає всі бібліотеки та плагіни в локальному репозиторії і навіть не пробує стукатися до центральних репозиторіїв за апдейтом тощо. Також корисно з повільним та нестабільним інтернетом.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Проперті &lt;code&gt;maven.test.skip&lt;/code&gt; поможе виконати компіляцію та збірку проекту без виконання тестів. Корисно, коли середовище для тестування не готово або ж з тестами все ок, а проблема з якимись плагінами або просто треба зібрати проект, щоб викласти десь. Може запускатися таким чином: &lt;code&gt;mvn install -Dmaven.test.skip=true&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Файл &lt;code&gt;MVN_HOME/conf/settings.xml&lt;/code&gt; містить ряд корисних настройок. Однією з них є &lt;code&gt;localRepository&lt;/code&gt;, за допомогою якої можна вказати шлях до репозиторія десь на диску відмінному від C:. Користувачі windows часто форматують C: і рідко бекаплять репозиторій. Правильний шлях може зберегти чимало часу при перевстановленні windows наступного разу.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Якщо використовується плагін мавена для генерації &lt;code&gt;javadoc&lt;/code&gt; для проекта з декількома модулями, то може бути дуже корисно виконати агрегації згенерованої документації, а для цього можна скористатися властивістю &lt;code&gt;&lt;span style="font-weight:bold;"&gt;aggregate&lt;/span&gt;&lt;/code&gt;, наприклад:&lt;br /&gt;  &lt;code&gt;&lt;br /&gt;         &amp;lt;plugin&amp;gt;&lt;br /&gt;         &amp;nbsp;   &amp;lt;artifactId&amp;gt;maven-javadoc-plugin&amp;gt;/artifactId&amp;gt;&lt;br /&gt;         &amp;nbsp;&amp;nbsp;   &amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;                &lt;span style="font-weight:bold;"&gt;&amp;lt;aggregate&amp;gt;true&amp;lt;/aggregate&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;            &amp;lt;/configuration&amp;gt;&lt;br /&gt;         &amp;lt;/plugin&amp;gt;&lt;br /&gt;  &lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Список не повний, буду його розширювати як тільки буду згадувати та знаходити нові тіпси.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7268316280927213413?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7268316280927213413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7268316280927213413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7268316280927213413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7268316280927213413'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/05/few-maven-tips.html' title='Maven допоможе!'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8009793905862133373</id><published>2009-07-06T00:48:00.006+03:00</published><updated>2009-07-14T03:13:15.987+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>A Few Maven Tips</title><content type='html'>&lt;script type="text/javascript"&gt;var dzone_url = 'http://java-ua.blogspot.com/2009/07/few-maven-tips.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'A Few Maven Tips';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;br /&gt;Decided to write some useful things, which often helps in everyday life to Maven user, like me: &lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;The command line argument &lt;code&gt;-o&lt;/code&gt; said to Maven to work in offline mode and this sometimes saves time. In this case, maven is lookіng for all the libraries and plugins in the local repository and do not even tries to ping central repositories for update. Also useful with slow and unstable Internet connection. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Property &lt;code&gt;maven.test.skip&lt;/code&gt; helps to perform project compilation without running test cases. Could be useful when the environment is not yet ready for testing or all tests green.  Run command in next format: &lt;code&gt;mvn install -Dmaven.test.skip=true&lt;/code&gt;.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;File &lt;code&gt;MVN_HOME/conf/settings.xml&lt;/code&gt; contains a number of useful settings. One of them is &lt;code&gt;localRepository&lt;/code&gt;, through which you can specify the repository somewhere on the disk D: etc. Windows users oftenly format drive C: and rarely backups local Maven repository. Correct value for this setting can save a lot of time after re-installing windows next time. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If you are using Maven plugin to generate Javadoc for a project with multiple modules, it can be very useful to perform the aggregation of generated documentation. In this case use property &lt;code&gt;aggregate&lt;/code&gt;, for example: &lt;br /&gt;&lt;code&gt;&lt;br /&gt;         &amp;lt;plugin&amp;gt;&lt;br /&gt;         &amp;nbsp;   &amp;lt;artifactId&amp;gt;maven-javadoc-plugin&amp;gt;/artifactId&amp;gt;&lt;br /&gt;         &amp;nbsp;&amp;nbsp;   &amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;                &lt;span style="font-weight:bold;"&gt;&amp;lt;aggregate&amp;gt;true&amp;lt;/aggregate&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;            &amp;lt;/configuration&amp;gt;&lt;br /&gt;         &amp;lt;/plugin&amp;gt;&lt;br /&gt;  &lt;/code&gt;&lt;/li&gt; &lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;The list is not complete, it will expand as soon as I remember or find new tips.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8009793905862133373?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8009793905862133373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8009793905862133373' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8009793905862133373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8009793905862133373'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/07/few-maven-tips.html' title='A Few Maven Tips'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5656918433344922920</id><published>2009-07-05T22:30:00.000+03:00</published><updated>2009-07-06T01:20:39.196+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JasperReports'/><title type='text'>Динамічний репорт за допомогою JasperReports</title><content type='html'>На проекті, над яким я працював десь рік тому, постала задача виконувати динамічну генерацію друкованої версії звіту. На проекті для генерації звітів використовувався JasperReports.&lt;br /&gt;Отже, постали наступні питання&lt;br /&gt;1. Як виконувати динамічну генерацію звіту: &lt;br /&gt; - чи є для цього API,&lt;br /&gt; - чи все-таки генерувати XML, а потім його компілювати?&lt;br /&gt;2. Як передавати дані?&lt;br /&gt;&lt;br /&gt;При виборі способу генерації динамічного звіту я вирішив використати перший варіант - працювати із API JasperReports для формування представлення звіту. Ідея генерувати XML в коді мені не дуже подобалася, тому що в цьому випадку код виглядав для мене заплутаним. Крім того, зміна версії бібліотеки могла привести до помилки, яку би було тяжко визначити. З API ситуація була інакшою: досягалася непогана чистота коду із можливістю абстрагування для різних видів звітів. Та й при компіляції можна було визначити сумісність використовуваного API із версією бібліотеки.&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;Дивно, але на той час мене чомусь не осягнула ідея використовувати JSP, Velocity чи FreeMarker для генерації шаблону звіту. Мені здається, що на даний момент я би використав саме цей спосіб.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Тут дуже знадобився такий клас як JasperDesign та набір класів сімейства Design. До класів сімейства Design відносяться:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JRDesignField&lt;/li&gt;&lt;li&gt;JRDesignStyle&lt;/li&gt;&lt;li&gt;JRDesignStaticText&lt;/li&gt;&lt;li&gt;JRDesignTextField&lt;/li&gt;&lt;li&gt;JRDesignExpression&lt;/li&gt;&lt;li&gt;JRDesignBand&lt;/li&gt;&lt;li&gt;і багато інших.&lt;/li&gt;&lt;/ul&gt;Перелічені вище класи є найбільш використовуваними. І якщо ви працювали колись із JasperReports, створюючи звіти за допомогою JRXML файла, то вам можуть бути знайомі такі елементи, як field, style, staticText, textField, band тощо. Суть використання Design класів полягає в тому, що вони представляють собою ті ж самі елементи JRXML. Обєктна модель справді дуже проста і зручна в розумінні.&lt;br /&gt;Створювати репорти динамічно просто і зручно. Але це є виключною ситуацією, оскільки завжди можна скористатися вашим олюбленим редактором XML або ж iReport.&lt;br /&gt;&lt;br /&gt;Мені свого часу довелося створити чимало репортів за допомогою Jasper. Більшість шаблонів створювалися в редакторі XML, чимало динамічних створювалися в коді і могли поєднювати ще декілька динамічних репортів, інші просто накидувалися швидкоруч в iReport.&lt;br /&gt;&lt;br /&gt;Для тих, кому цікаво, хочу привести декілька прикладів використання API JasperReport.&lt;br /&gt;&lt;br /&gt;Створення елементів звіту:&lt;br /&gt;&lt;pre class="java"&gt;&lt;br /&gt;     public static JRStyle getDefaultStyle() {&lt;br /&gt;        JRDesignStyle style = new JRDesignStyle();&lt;br /&gt;        style.setName("defaultStyle");&lt;br /&gt;        style.setDefault(true);&lt;br /&gt;        style.setFontName("Arial");&lt;br /&gt;        style.setFontSize(8);&lt;br /&gt;        style.setPdfFontName("/TTF/arial.ttf");&lt;br /&gt;        style.setPdfEncoding("Identity-H");&lt;br /&gt;        style.setPdfEmbedded(true);&lt;br /&gt;        return style;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static JRStyle getHeadStyle() {&lt;br /&gt;        JRDesignStyle style = new JRDesignStyle();&lt;br /&gt;        style.setName("headStyle");&lt;br /&gt;        style.setDefault(true);&lt;br /&gt;        style.setFontName("Arial");&lt;br /&gt;        style.setFontSize(8);&lt;br /&gt;        style.setBold(true);&lt;br /&gt;        style.setPdfFontName("/TTF/arial.ttf");&lt;br /&gt;        style.setPdfEncoding("Identity-H");&lt;br /&gt;        style.setPdfEmbedded(true);&lt;br /&gt;        return style;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static JRDesignElement staticTextElement(String text,&lt;br /&gt;                                                    int height, int width,&lt;br /&gt;                                                    int x, int y,&lt;br /&gt;                                                    boolean headStyle) {&lt;br /&gt;        JRDesignStaticText staticText = new JRDesignStaticText();&lt;br /&gt;        staticText.setText(text);&lt;br /&gt;        staticText.setWidth(width);&lt;br /&gt;        staticText.setHeight(height);&lt;br /&gt;        staticText.setX(x);&lt;br /&gt;        staticText.setY(y);&lt;br /&gt;        staticText.setBorder(JRGraphicElement.PEN_THIN);&lt;br /&gt;        if (headStyle) staticText.setStyle(getHeadStyle());&lt;br /&gt;&lt;br /&gt;        return staticText;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static JRDesignElement textFieldElement(String text, Class type,&lt;br /&gt;                                                   int height, int width,&lt;br /&gt;                                                   int x, int y,&lt;br /&gt;                                                   boolean headStyle) {&lt;br /&gt;        JRDesignTextField textField = new JRDesignTextField();&lt;br /&gt;        textField.setWidth(width);&lt;br /&gt;        textField.setHeight(height);&lt;br /&gt;        textField.setX(x);&lt;br /&gt;        textField.setY(y);&lt;br /&gt;        textField.setBorder(JRGraphicElement.PEN_THIN);&lt;br /&gt;        if (headStyle) textField.setStyle(getHeadStyle());&lt;br /&gt;&lt;br /&gt;        JRDesignExpression expression = new JRDesignExpression();&lt;br /&gt;        expression.setText(text);&lt;br /&gt;        expression.setValueClassName(type.getName());&lt;br /&gt;        textField.setExpression(expression);&lt;br /&gt;&lt;br /&gt;        return textField;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static JRDesignElement textFieldElement(Property property,&lt;br /&gt;                                                   int height, int width,&lt;br /&gt;                                                   int x, int y,&lt;br /&gt;                                                   boolean headStyle) {&lt;br /&gt;        JRDesignTextField textField = new JRDesignTextField();&lt;br /&gt;        textField.setWidth(width);&lt;br /&gt;        textField.setHeight(height);&lt;br /&gt;        textField.setX(x);&lt;br /&gt;        textField.setY(y);&lt;br /&gt;        textField.setBorder(JRGraphicElement.PEN_THIN);&lt;br /&gt;        if (headStyle) textField.setStyle(getHeadStyle());&lt;br /&gt;&lt;br /&gt;        JRDesignExpression expression = new JRDesignExpression();&lt;br /&gt;        expression.setValueClassName(property.getType().getName());&lt;br /&gt;        if (property instanceof Column) {&lt;br /&gt;            expression.addFieldChunk(property.getName());&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            expression.addParameterChunk(property.getName());&lt;br /&gt;        }&lt;br /&gt;        textField.setExpression(expression);&lt;br /&gt;&lt;br /&gt;        return textField;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ініціалізація звіту:&lt;br /&gt;&lt;pre class="java"&gt;&lt;br /&gt;    JasperDesign reportDesign = new JasperDesign();&lt;br /&gt;    reportDesign.setName(context.getDataResult().getDataReport().reportType().getReportName());&lt;br /&gt;    reportDesign.setOrientation(JasperDesign.ORIENTATION_LANDSCAPE);&lt;br /&gt;    reportDesign.setIgnorePagination(true);&lt;br /&gt;    reportDesign.setTopMargin(5);&lt;br /&gt;    reportDesign.setBottomMargin(5);&lt;br /&gt;    reportDesign.setLeftMargin(5);&lt;br /&gt;    reportDesign.setRightMargin(5);&lt;br /&gt;    reportDesign.setWhenNoDataType(JasperDesign.WHEN_NO_DATA_TYPE_NO_PAGES);&lt;br /&gt;&lt;br /&gt;    reportDesign.addImport("java.lang.*");&lt;br /&gt;    reportDesign.addImport("java.math.*");&lt;br /&gt;    reportDesign.addImport("java.util.*");&lt;br /&gt;    reportDesign.addImport("net.sf.jasperreports.engine.*");&lt;br /&gt;    reportDesign.addImport("net.sf.jasperreports.engine.data.*");&lt;br /&gt;&lt;br /&gt;    reportDesign.addStyle(getDefaultStyle());&lt;br /&gt;    reportDesign.addStyle(getHeadStyle());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Заповнення звіту:&lt;br /&gt;&lt;pre class="java"&gt;&lt;br /&gt;    JRDesignBand rootBand = new JRDesignBand();&lt;br /&gt;    rootBand.setHeight(40);&lt;br /&gt;    rootBand.setSplitAllowed(true);&lt;br /&gt;    reportDesign.setDetail(rootBand); // could be setTitle() or setSummary() etc.&lt;br /&gt;&lt;br /&gt;    rootBand.addElement(textFieldElement("Details", String.class, &lt;br /&gt;            height, 120, currentX, currentY, false));&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Компіляція звіту:&lt;br /&gt;&lt;pre class="java"&gt;&lt;br /&gt;    JasperReport compileReport(JasperDesign reportDesign) throws ReportException {&lt;br /&gt;        try {&lt;br /&gt;            log.info("Compiling report...");&lt;br /&gt;            return JasperCompileManager.compileReport(reportDesign);&lt;br /&gt;        }&lt;br /&gt;        catch (Exception e) {&lt;br /&gt;            log.error("Error to compile report, cause:", e);&lt;br /&gt;            throw new ReportException("Error to compile report!", e);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Використання отриманого &lt;code&gt;JasperReport&lt;/code&gt;:&lt;br /&gt;&lt;pre class="java"&gt;&lt;br /&gt;    JasperDesign reportDesign = new JasperDesign();&lt;br /&gt;&lt;br /&gt;    //&lt;br /&gt;    // preparing and filling report design goes here...&lt;br /&gt;    //&lt;br /&gt;    &lt;br /&gt;    JasperReport jasperReport = compileReport(jasperDesign);&lt;br /&gt;    JasperPrint jasperPrint  = JasperFillManager.fillReport(&lt;br /&gt;           jasperReport, prepareParameters(), prepareDataSource());&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5656918433344922920?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5656918433344922920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5656918433344922920' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5656918433344922920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5656918433344922920'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/02/jasperreports.html' title='Динамічний репорт за допомогою JasperReports'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4667488288583965830</id><published>2009-05-09T23:13:00.013+03:00</published><updated>2009-05-10T00:27:49.853+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uml'/><title type='text'>yUML</title><content type='html'>Just linked &lt;a href="http://yuml.me/"&gt;yUML&lt;/a&gt; to my blog. I like that service. &lt;br /&gt;There are also few articles about it &lt;a href="http://www.tobinharris.com/blog"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There are next few yUML samples:&lt;br /&gt;&lt;div class="diagram"&gt;[Document]&lt;0..*-1[DocumentTemplate],[DocumentTemplate]-^[Template]&lt;/div&gt;&lt;br /&gt;&lt;div class="diagram"&gt;[DocumentTemplate]-^[Template],[ReportTemplate]-^[Template|-name;-author;-location|open();save();remove()],[FigureTemplate]-^[Template]&lt;/div&gt;&lt;br /&gt;&lt;div class="ucdiagram"&gt;[Administrator]-(Create Template),[Administrator]-(Create Document)&lt;/div&gt;&lt;br /&gt;And now Scruffy variant:&lt;br /&gt;&lt;div class="sdiagram"&gt;[Document]&lt;0..*-1[DocumentTemplate],[DocumentTemplate]-^[Template],[ReportTemplate]-^[Template],[FigureTemplate]-^[Template],[Template]-&gt;[Author|firstName;lastName],[Template]-&gt;[Resource|fileName;type;version]&lt;/div&gt;&lt;br /&gt;&lt;div class="ucsdiagram"&gt;[Ruslan]-(Create Article), [Ruslan]-(Edit Article),&lt;br /&gt;[Ruslan]-(Write Comments)&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Looks great, isn't it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4667488288583965830?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4667488288583965830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4667488288583965830' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4667488288583965830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4667488288583965830'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/05/yuml.html' title='yUML'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6497414959240794926</id><published>2009-05-09T11:28:00.003+03:00</published><updated>2009-05-09T17:51:27.870+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='presentation'/><title type='text'>Linus about Git</title><content type='html'>Перше серйозне знайомство з Git було в мене після перегляду відео презентації Лінусом Торвальдсом, на якій він розсказував наскільки Git крутий, а майже все інше близьке до лайна. Як на мене, занадто він впевнено про це заявляв, але і мені Git сподобався тоже.&lt;br /&gt;&lt;br /&gt;Відео було на англійській мові, але не давно знайшов переклад цього відео. Точніше, переклад слів Торвальдса.&lt;br /&gt;&lt;a href="http://lib.custis.ru/index.php/Линус_Торвальдс_о_GIT_на_Google_Talks"&gt;http://lib.custis.ru/index.php/Линус_Торвальдс_о_GIT_на_Google_Talks&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6497414959240794926?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6497414959240794926/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6497414959240794926' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6497414959240794926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6497414959240794926'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/05/linus-about-git.html' title='Linus about Git'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1642746082829343991</id><published>2009-04-25T01:55:00.008+03:00</published><updated>2009-04-27T01:36:08.294+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Git and Subversion works together</title><content type='html'>I like the idea to use Subversion central repository with a Git local "stub" repository. With having local Git repository I have access to the all history of some branch or trunk, as I have a local copy of Subversion repository. Local commits and easy branching is a big plush for me too. &lt;br /&gt;&lt;br /&gt;Most of us are working with Subversion repositories, as they are wide used and popular nowadays. These tool gives us advantages to work with branches, setup security, transaction commits and many more. While Git proposes easy and low cost branching, decentralized storing and low coupling developers interaction. Yes, I said low coupling, as 2 developers that are working on the same thing in parallel now are able to synchronize code locally, without central repository.&lt;br /&gt;&lt;br /&gt;I don't know what is your experience with merging branches using Subversion, but for me it's a hell. With a few different branches, that are ready to be merged into trunk but is not, because "we don't need it in trunk now, but maybe in 2 weeks we will". Sometimes merging takes the same time as new feature development.&lt;br /&gt;&lt;br /&gt;Now Git can help us with it, as has new operation &lt;code&gt;git svn&lt;/code&gt;.&lt;br /&gt;It's currently working fine on Linux, but you should be ready to get some unpredictable behavior on Windows. Expecting that with 1.6.3 and latest versions git-svn will work much better that with Git-1.6.2.2-preview20090408.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1642746082829343991?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1642746082829343991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1642746082829343991' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1642746082829343991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1642746082829343991'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/04/git-and-subversion-works-together.html' title='Git and Subversion works together'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6800426997370900208</id><published>2009-04-12T16:56:00.007+03:00</published><updated>2009-04-12T17:32:08.336+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Git Advantages</title><content type='html'>Побавився сьогодні трохи з Git. Досі я в основному працював з SVN, і тільки із централізованими системами контролю версій.&lt;br /&gt;В Git знайшов кілька цікавих речей, які мені ясно сподобалися, а саме:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; Розприділені SCM дозволяють мати локальний репозиторій, з яким працювати є набагато зручніше. Адже він &lt;br /&gt;завжди зі мною, я можу виконувати кілька незалежних комітів, які просто потім відправляти в публічний репозиторій, коли є необхідність і можливість. Розприділені репозиторії дозволять мені також синхронізуватися з іншими програмістами без необхідності внесення змін в публічний репозиторій.&lt;br /&gt;&lt;li&gt; Можливість створювати декілька commit lists, для того щоб комітити різні зміни із різними коментарями. Дуже корисно для підтримки порядку.&lt;br /&gt;&lt;li&gt; Можливість вибудовувати ієрархію репозиторіїв. Розприділення відповідальності між програмістами тепер може бути на рівні окремого репозиторію. Річ цікава і корисна, і якщо коли-не-будь доводилося працювати із репозиторіями, що знаходяться на іншому кінці світу, заховані за тучою файерволів і взагалі частенько є недоступними, тоді мене можна буде зрозуміти.&lt;br /&gt;&lt;li&gt; Можливість вносити зміни в історію комітів, наприклад, видалити зайвий файл або підкорегувати коментар.&lt;br /&gt;&lt;li&gt; Зручна та швидка робота із бренчами.&lt;br /&gt;&lt;li&gt; Message при коміті є обов'язковим.&lt;br /&gt;&lt;li&gt; Зручна робота із git в консолі.&lt;br /&gt;&lt;li&gt; Нема необхідності виконувати бекапи публічного репозиторію, якщо є декілька програмістів, що мають його локальну копію.&lt;br /&gt;&lt;/oL&gt;&lt;br /&gt;Це тільки декілька можливостей. Мені вони здалися найкориснішими.&lt;br /&gt;Звичайно, частину з них можна добитися і від SVN, але для цього треба докласти чимало часу, а інколи і грошей.&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Знайшов гарну статтю про переваги Git над SVN: &lt;a href="http://git.or.cz/gitwiki/GitSvnComparsion"&gt;http://git.or.cz/gitwiki/GitSvnComparsion&lt;/a&gt; і навпаки.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6800426997370900208?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6800426997370900208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6800426997370900208' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6800426997370900208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6800426997370900208'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/04/git-advantages.html' title='Git Advantages'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7543357565210831242</id><published>2009-03-22T21:52:00.004+02:00</published><updated>2009-03-22T21:57:13.391+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>ClearFont setup tool for WinXP</title><content type='html'>Не великий секрет - я користуюся Windows XP і наразі для мене це найкраща ОС. А заради відчуття красивого вмикаю я згладжування шрифтів ClearType. &lt;br /&gt;Ось тільки кілька місяців тому змушений був відмовитися, адже на новому моніторі це згладжування виглядало просто огидно. Але не так давно знайшов прикольну тулзу від майкрософта &lt;a href="http://www.microsoft.com/typography/ClearTypePowerToy.mspx"&gt;http://www.microsoft.com/typography/ClearTypePowerToy.mspx&lt;/a&gt;.&lt;br /&gt;Після вельми простої конфігурації, я отримав хорошу якість згладжування шрифтів.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7543357565210831242?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7543357565210831242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7543357565210831242' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7543357565210831242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7543357565210831242'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/03/clearfont-setup-tool-for-winxp.html' title='ClearFont setup tool for WinXP'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1849738381615488356</id><published>2009-03-22T21:25:00.004+02:00</published><updated>2009-03-22T21:45:23.933+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>System.nanoTime() and measurements</title><content type='html'>I'm still using simple &lt;code&gt;System.currentTimeMillis()&lt;/code&gt; when need to test performance of some part of code. It's fast and easy to use, especially to profile some algorithm while coding; performance still is an important measure used to choose between few algorithms or choose the best way how to implement algorithm.&lt;br /&gt;But for some algorithms, especially in development environment &lt;code&gt;System.currentTimeMillis()&lt;/code&gt; doesn't give any valuable results as it's hard to choose between 0ms and 0ms returned for both algorithms :) &lt;code&gt;System.nanoTime()&lt;/code&gt; can used in such situations. It helps to get precise measurement of code execution time.&lt;br /&gt;But, everyone will say that it is not important what way of implementation you'll choose if difference is less than 1ms. It doesn't matter. And they will be right. In this case it doesn't matter what is faster, even if production amount of data is much more than testing amount of data and this may affect execution time significantly. Algorithm does matter. &lt;br /&gt;&lt;br /&gt;It always depends on algorithm!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1849738381615488356?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1849738381615488356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1849738381615488356' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1849738381615488356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1849738381615488356'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/03/systemnanotime-and-measurements.html' title='System.nanoTime() and measurements'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5416183782683950690</id><published>2009-03-14T08:21:00.014+02:00</published><updated>2009-03-22T21:48:33.974+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='refcardz'/><category scheme='http://www.blogger.com/atom/ns#' term='RichFaces'/><title type='text'>JBoss Richfaces Refcard is ready for free download</title><content type='html'>&lt;a href="http://dzone.com"&gt;DZone&lt;/a&gt; provides a list of free to download and use refcards for different technologies and tools (like IDE). Few days ago new refcard was release, and it's about JBoss Richfaces. You may download it here &lt;a href="http://refcardz.dzone.com/refcardz/richfaces"&gt;http://refcardz.dzone.com/refcardz/richfaces&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;At page &lt;a href="http://refcardz.dzone.com/"&gt;http://refcardz.dzone.com/&lt;/a&gt; you may download more and more refcards for yourself. Some time ago I've downloaded for &lt;a href="http://eclipse.org"&gt;Eclipse&lt;/a&gt;, my favorite IDE &lt;a href="http://jetbrains.com/idea"&gt;IntellijIDEA&lt;/a&gt;, &lt;a href="http://springframework.org"&gt;Spring&lt;/a&gt;, &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; etc. And now downoloading JBoss Richfaces refcard too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5416183782683950690?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5416183782683950690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5416183782683950690' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5416183782683950690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5416183782683950690'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/03/jboss-richfaces-refcard-is-ready-for.html' title='JBoss Richfaces Refcard is ready for free download'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4703384723550017145</id><published>2009-03-04T21:37:00.006+02:00</published><updated>2009-03-04T22:13:12.130+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Scalable'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Presentations and articles about scalable software architecture</title><content type='html'>Last week was searching for interesting articles and presentations with samples of scalable and failure tolerant architecture. As result, my bookmarks increased with a number of new links to articles and videos.&lt;br /&gt;&lt;br /&gt;Articles:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/articles/scalability-principles"&gt;Scalability Principles&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf"&gt;SEDA&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://mikenereson.blogspot.com/2007/06/spring-on-code-organization-for-large.html"&gt;Large codebase organization with Spring&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/articles/scalability-panel"&gt;Building Scalability and Achieving Performance: A Virtual Panel&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/articles/scalability-worst-practices"&gt;Scalability Worst Practices&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.addsimplicity.com/adding_simplicity_an_engi/2008/08/shard-lessons.html"&gt;Shard Lessons&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.webperformancematters.com/journal/2007/8/21/asynchronous-architectures-4.html"&gt;Asynchronous Architectures [4]&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://esammer.blogspot.com/2009/02/principles-of-architecture-reduce-and.html"&gt;Thoughts on Development&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://davidvancouvering.blogspot.com/2009/02/hitting-scalability-wall-amdahls-law.html"&gt;Hitting the scalability wall - Amdahl's Law&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.caffeinatedcoder.com/10-lessons-in-scalability-from-myspace/"&gt;10 Lessons in Scalability from MySpace&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://natishalom.typepad.com/nati_shaloms_blog/2008/05/twitter-as-an-e.html"&gt;Twitter as a scalability case study&lt;/a&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Videos &amp; presentations:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/presentations/shoup-ebay-architectural-principles"&gt;Randy Shoup on eBay's Architectural Principles&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/presentations/architecture-evaluation"&gt;Architecture Evaluation in Practice&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/presentations/availability-consistency"&gt;Availability &amp; Consistency&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/presentations/Architecting-Latency-Dan-Pritchett"&gt;Architecting for Latency&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/presentations/design-and-architecture-of-infoq"&gt;The Design and Architecture of InfoQ&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/presentations/operational-manageability"&gt;Architecture Quality: Operational Manageability&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.slideshare.net/Georgio_1999/how-to-scale-your-web-app"&gt;How to scale your web app&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.infoq.com/presentations/MySpace-Dan-Farino"&gt;Behind the Scenes at MySpace.com&lt;/a&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.slideshare.net/Blaine/scaling-twitter"&gt;Scaling Twitter&lt;/a&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://java-ua.blogspot.com/2009/03/presentations-and-articles-about.html';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Presentations and articles about Software Architecture';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;&lt;br /&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4703384723550017145?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4703384723550017145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4703384723550017145' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4703384723550017145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4703384723550017145'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/03/presentations-and-articles-about.html' title='Presentations and articles about scalable software architecture'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6107961306929488330</id><published>2009-03-04T21:04:00.006+02:00</published><updated>2010-11-17T21:30:08.509+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><title type='text'>Cловники в предметній області</title><content type='html'>Словники предметної області займають вельми важливе місце при проектуванні та розробці  програмного забезпечення. Не менш частіше використовуються словники в предметній області. В даному випадку, словниками можуть виступати невеликі набори даних в стилі ключ-значення, або більш складні, де кожному ключу відповідає набір значень. Прикладів таких словників є безліч, наприклад, словник країн, словник типів кредитних карточок, словник пріоритетів задач, і більш складніші словники матеріалів та продукції (за окремими вийнятками) тощо.&lt;br /&gt;&lt;br /&gt;Ця стаття розповідає про моє бачення такого "патерна" як &lt;i&gt;Словник&lt;/i&gt;. Важливо визначитися, що саме слід вважати словником в предметній області. &lt;br /&gt;&lt;br /&gt;Словник – це набір термінів пов’язаних між собою певною областю використання, які проте рідко змінюються. Частіше всього, словники використовуються, для того, щоб надати користувачам вибір значень з певної множити, наприклад, країну проживання, стать, посаду тощо. &lt;br /&gt;&lt;br /&gt;Словники складаються з записів, які собою являють пару ключ-значення. В залежності від значення словники бувають простими та складними. Простий словник, це коли певному ключу відповідає одне значення, а складний словник – ключу відповідає набір значення. Наприклад, якщо коду країни відповідає тільки назва цієї країни, то цей словник є простим, де ключем виступає код країни. Прикладом складного словника є словник матеріалів, де коду товару відповідає його назва, вартість, країна виробник, маса тощо.&lt;br /&gt;&lt;br /&gt;Складні словники можуть бути складеними. Складеним словником називається такий, в якого одне із значень є елементом іншого словниками. Наприклад, дано складний словник країн, в якому певному коду відповідають назва та код типу країни (республіка, федерація, королівство тощо). Код типу країни вказує на словник типів країн, таким чином словник країни можна вважати складеним та залежним від словника типів країн.&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;br /&gt; &lt;img src="http://farm4.static.flickr.com/3412/3329134642_316d0d8a1c_o.png"/&gt;&lt;br /&gt; Рис 1 – Різні типи словників.&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Словники часто використовують при розробці програмного забезпечення, адже дають можливість групувати набори даних в окремі групи, використовувати їх в групах та асоціювати певне значення з групою. В предметної області певний набір даних може бути словником, якщо він не виступає центральним в даній предметній області. Словники повинні залишатися максимально спрощеним та піддававтися мінімальним змінам в процесі використання, в той час як центральні сутності предметної можуть бути дуже складними та змінювати часто.&lt;br /&gt;&lt;br /&gt;Чим складніший словник, тим більше програмний продукт залежить від нього. Словники можуть з часом переростати на повноцінні набори даних. При цьому збільшується або їх складності або кількість даних.&lt;br /&gt;&lt;br /&gt;Зі словників часто починається проектування та кодування програм, вони є об’єктом перевикористання. Якщо використовувати необхідні словники спроектовані та закодовані на попередніх проектах, то можна скоротити час на написання нових проектів. Розроблений словник може виступати незалежним компонентом, але подібні компоненти буває тяжко спроектувати, адже вони вимагають гнучкості в роботі, а також тісної залежності від них іншого коду.&lt;br /&gt;&lt;br /&gt;Існує кілька способів зберігання даних словників: набори констант, енумерації, файли, база даних тощо. Використання констант та енумерації для зберігання елементів словника пожуть значно покращити процес кодувати та збільшити читабельність коду, але при цьому частіше всього ми втрачаємо можливість швидкої зміни «захардкодженого» набору даних. Звичайно, словник статей, може бути спокійно закодований у вигляді енумерації, але словник країн ні. Те, що словники змінюються рідко не значить, що вони ніколи не міняються. В окремих випадках є необхідність добавити нові елементи або виконати користування існуючих, і в залежності від типу програми, найкращими будуть тут зберігання словників у файлах та базах даних. &lt;br /&gt;&lt;br /&gt;Ще однією хорошою практикою є змістовні ключі словників. Простіше працювати та підтримувати в роботі словники, що містять ключі, які легко зрозуміти та отримати інформацію про сам елемент словника. Цього тяжко досягнути якщо використовувати числові ідентифікатори. Наприклад, для словника типів кредитних карточок ключі VISA, MSTR, AMEX тощо зручніше використовувати, ніж, наприклад, 1, 2, 3. У випадку використання бази даних для зберігання словників також простіше писати запити.&lt;br /&gt;Оскільки словники містять невеликі набори даних і в основному рідко змінюються, то вони частіше легко піддаються кешуванню. Але тут слід не забувати, що словники теж можуть міняти, тому програма повинна підтримувати або можливість обновити дані в кеші або виконати інвалідацію кеша або ж увімкнути підтримку дати закінчення терміни дії кешу, після якого нові дані будуть знов закешовані.&lt;br /&gt;&lt;br /&gt;Для зберігання та використання словників можна також використовувати і інші способи. Наприклад, якщо використовується MySQL, то для роботи із таблицями з словниками можна використвувати MyISAM engine, адже він найкраще підходить для даних, що рідко змінуюються, але частіше зчитуються. Таблиці із словниками частіше піддаються повному кешуванню СУБД, а використання сладених індексів на всі колонки БД може взагалі позбавити необхідность у фізичному вводі-виводі. Збереження словників у базі даних та використання зовнішніх ключів покращує цілісність даних, і знову ж таки, не сильно впливає на ресурси для виконання запитів.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6107961306929488330?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6107961306929488330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6107961306929488330' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6107961306929488330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6107961306929488330'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/03/c.html' title='Cловники в предметній області'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8047886930512052139</id><published>2009-02-12T01:08:00.022+02:00</published><updated>2009-02-25T06:44:02.732+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Spring MVC and RESTful web service.</title><content type='html'>This article is a result of my experience on building small RESTful web service using &lt;a href="http://springframework.org"&gt;SpringMVC 2.5&lt;/a&gt;. Web service is simple, it supports only few operations, most of them just retrieves data and sends back it in XML.&lt;br /&gt;&lt;br /&gt;Well, the task is simple enough: &lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;build secured web service for mostly getting and sometimes posting data; &lt;br /&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;REST&lt;/a&gt; interface is required&lt;br /&gt;&lt;ul&gt;&lt;li&gt; but SOAP could be added later (I think that if you build SOAP web service you should wait that you'll need to provide REST API  for this web service too and vise versa). &lt;/ul&gt;&lt;/ol&gt;&lt;br /&gt;As web service is build with REST philosophy, than we need to support processing of GET, POST (well, for me it's enough) requests and return data as XML or JSON. Spring MVC as well others REST web service frameworks and API help with this too. So, what's next? &lt;br /&gt;&lt;br /&gt;As application is build with Spring 2.5, it was the best to have some framework for building REST web service easily and easily to integrate it with Spring. Not a secret, that Spring MVC integrates with Spring better that any other web framework or REST web service framework (hm, maybe it's because it is build on Spring). Well, this is cons for using Spring MVC and it is good, but truly - this not enough yet. &lt;br /&gt;&lt;br /&gt;Yet one requirement: SOAP web service could be added later. And if it could be added than (in most cases) it will be added. This is important, very important, because we want to build easy-to-extend software. And in case of SOAP WS I prefer to use Spring WS, that is well integrated with Spring MVC. Need also to take into consideration that some REST web service frameworks hardly integrates with Spring MVC or wanted to process all requests. That is a great pros for using Spring MVC.&lt;br /&gt;&lt;br /&gt;You may understand what I'm implying. Yes, Spring MVC will be used to build RESTful web service. &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Architecture&lt;/h4&gt;&lt;br /&gt;The main goals of architecture are:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt; be scalable (not to much, but enough to process thousands of requests per hour)&lt;br /&gt; &lt;li&gt; be extendable (SOAP must be easy to add)&lt;br /&gt; &lt;li&gt; do what is required and nothing more&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Next decisions were made:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt; request should be stateless&lt;br /&gt; &lt;li&gt; each request should be processed as quick as possible&lt;br /&gt; &lt;li&gt; there will be 2 levels of caching: one cache for entities and queries (used by web service backend service), and another cache for rendered XML response (used by web service endpoint).&lt;br /&gt; &lt;li&gt; everything that could be changed is configured through simple XML configuration (i.e. cache configuration, security configuration, business logic configuration etc.)&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The main result of made decisions &amp; rules is request processing lifecycle, that consists of next few phases:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt; Authentification &amp; Authorization (security filter)&lt;br /&gt; &lt;li&gt; Getting request parameters. Web service endpoint (in our case it is SpringMVC controller) parses request parameters and validates them. &lt;br /&gt; &lt;li&gt; If everything is okay than it tries to get XML response from cache and sends it as response to the client. This step is optional and is processed only if cache is enabled and client does not specify request as such that ignores cache.&lt;br /&gt; &lt;li&gt; Endpoint determines the appropriate WebService backend service and run it and get results.&lt;br /&gt; &lt;li&gt; Endpoint converts results into XML, prepare response and stores it at cache (if cache is enabled). After the XML response is send back to client.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3584/3308437274_d0cf8d76e6_o.png"/&gt;&lt;br /&gt;&lt;br /&gt;So, if the request response is cached in 2nd or 1st cache levels, than response will be generated without hitting database. In my development environment caching helps to increase performance up to 1500%. In production this number is less - just 300-500%. Still these is very well.&lt;br /&gt;&lt;br /&gt;This lifecycle helps to build a scheme of responsibilities and modules. Later each responsibility could be processed by own server or a set of servers.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3559/3307606175_4eab66492c_o.png"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt; Simple implemenation &lt;/h4&gt;&lt;br /&gt;Spring 2.5 gave us possibility to use annotations as for declaring services as for declaring SpringMVC controllers. Spring's annotations &lt;code&gt;Controller, RequestMapping, RequestParam&lt;/code&gt; and flexible politic on request handle method parameters gives us brilliant instrument for building web service endpoint.&lt;br /&gt;Ofcourse, hardcoding of URLs in annotations looks as not the best way for building flexible and configurable application. But, this is quite pardonable, because we will use &lt;a href="http://tuckey.org/urlrewrite/"&gt;UrlRewriteFilter&lt;/a&gt;. UrlRewriteFilter is very useful tool, as it will helps to rewrite URLs, get parameters from URL and do other interesting things. But for our the most important are next 2 features:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;flexibility while mapping external URLs (used by users) to internal URLS (processed by endpoint controllers)&lt;br /&gt;&lt;li&gt;possibility to catch parameters from URL, e.g. http://example.com/book/edit/12 -&gt;&lt;br /&gt;http://exampl.com/book/edit?boodId=12 etc.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Lets look how we could use this features:&lt;br /&gt;Let we have RESTful web service that returns XML with information with specified by id book. Web service clients could get this information by requesting url&lt;br /&gt;http://ourservice.com/ws/rest/book/{bookId} (e.g. http://ourservice.com/ws/rest/book/12). Our application should handle this call and the information about book wit specified id.&lt;br /&gt;&lt;br /&gt;Here is our web service controller:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;@Controller&lt;br /&gt;public class WebServiceEndpoint {&lt;br /&gt;&lt;br /&gt;     @Autowired&lt;br /&gt;     private BookService bookService;&lt;br /&gt;&lt;br /&gt;     @RequestMapping(value = "webservice/book", methods = RequestMethod.GET)&lt;br /&gt;     public ModelAndView getBook(@RequestParam(name="bookID", required=true)int bookId, Map&amp;lt;String, Object&amp;gt; model) {&lt;br /&gt;         model.put("book", bookService.getBookById(bookId));&lt;br /&gt;         return new ModelAndView("template/ws/bookInfo", model);&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Code is very simple, but it's good as for sample.&lt;br /&gt;&lt;br /&gt;So, we have controller that processes all GET requests for &lt;code&gt;'webservice/book'&lt;/code&gt; resource, that should have request parameter of type integer with name 'bookID'. Endpoint just call backend service, gets information about book, put it to model map and return the &lt;code&gt;ModelAndView&lt;/code&gt; instance with simple template that will be rendered and returned to client. &lt;br /&gt;&lt;br /&gt;This endpoint controller can't be default process web service request. To redirect web service client request to our endpoint we will use UrlRewriteFilter&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;     &amp;lt;rule&amp;gt;&lt;br /&gt;        &amp;lt;from&amp;gt;^/ws/rest/book/[0-9]+$&amp;lt;/from&amp;gt;&lt;br /&gt;        &amp;lt;to&amp;gt;/webservice/book?bookID=$1&amp;lt;/to&amp;gt;&lt;br /&gt;     &amp;lt;/rule&amp;gt;&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;so request for resource &lt;code&gt;http://ourservice.com/ws/rest/book/12&lt;/code&gt; will be rewrited by filter to &lt;code&gt;http://ourservice.com/webservice/book?bookID=12&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's about all for now. The story looks to long. Most of us do not have enough time to read long articles :)&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://java-ua.blogspot.com/2009/02/spring-mvc-helps-to-build-restful-web.html';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Spring MVC and RESTful web service.';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;&lt;br /&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8047886930512052139?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8047886930512052139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8047886930512052139' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8047886930512052139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8047886930512052139'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/02/spring-mvc-helps-to-build-restful-web.html' title='Spring MVC and RESTful web service.'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7260755819086282400</id><published>2009-01-17T23:17:00.006+02:00</published><updated>2011-09-05T11:52:11.287+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Кешування (Caching)'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='cache'/><title type='text'>Simple LRU cache implementation.</title><content type='html'>By this &lt;a href="http://www.davidflanagan.com/blog/000014.html"&gt;url&lt;/a&gt; can be found post about using &lt;code&gt;LinkedHashMap&lt;/code&gt; as LRU cache. Also, I've found such code with a direct link as comment in &lt;a href="http://roller.apache.com"&gt;Apache Roller&lt;/a&gt; source code.&lt;br /&gt;&lt;code&gt;LinkedHashMap&lt;/code&gt; can be used as LRU cache because it supports ordering it's elements not only by insert order, but also by access-order. Also there is protected method &lt;code&gt;removeEldestEntry&lt;/code&gt; in the &lt;code&gt;LinkedHashMap&lt;/code&gt; that runs in the &lt;code&gt;put()&lt;/code&gt; and &lt;code&gt;putAll()&lt;/code&gt; methods. If that method returns true, than least recently inserted/accessed element will be removed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7260755819086282400?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7260755819086282400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7260755819086282400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7260755819086282400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7260755819086282400'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/01/simple-lru-cache-implementation.html' title='Simple LRU cache implementation.'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-414638958949686244</id><published>2009-01-14T10:49:00.010+02:00</published><updated>2009-01-14T11:24:36.354+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><title type='text'>You and your's sofware expansibility.</title><content type='html'>For a long time one of the scores of software I'm writing is &lt;i&gt;expansibility&lt;/i&gt;. That's mean how fast, with minimum of changes, I can add new features or extend existed one. &lt;br /&gt;I've made few notes and use them as often as possible. Here are they:&lt;br /&gt; - &lt;i&gt;Never&lt;/i&gt; or almost never &lt;i&gt;requirements&lt;/i&gt; you are working on &lt;i&gt;are complete&lt;/i&gt;. Even if customer told you that this is finish step and we stop work on it - that mean only - we stop the work for now and we may continue it after some time. And of course, that time may vary from few weeks to few month, so you may and you will forget the code. That's why always &lt;u&gt;write comments to the code even if it is not yours!&lt;/u&gt;&lt;br /&gt; - &lt;u&gt;If you can extend the code you've write before - do it!&lt;/u&gt; If you need to get the list of some entities - use search engine if it exists. If search engine is not enough - extend it and use it. &lt;u&gt;Be DRY principal follower!&lt;/u&gt;&lt;br /&gt; - Write your code with one think: &lt;u&gt;I will use it tomorrow too!&lt;/u&gt; That's mean that you should &lt;i&gt;write quality code, well commented code and code that make everything you have now and a little bit more.&lt;/i&gt; Sure, this &lt;i&gt;"a little bit more"&lt;/i&gt; should be result of your experience. If you don't have enough experience - use this too! Why? You'll get need experience much faster!&lt;br /&gt; - &lt;u&gt;Do code review! Often.&lt;/u&gt; Why? Because it increases the quality of your code and as result of software. And also you'll find your and yours colleagues weak and that is 50% of new experience. I like &lt;a href="http://atlassian.com"&gt;Atlassian&lt;/a&gt; experience with code reviewing for many tasks they do.&lt;br /&gt;&lt;br /&gt;Simple, but important.&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://java-ua.blogspot.com/2009/01/for-long-time-one-of-scores-of-software.html';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'You and your's sofware expansibility.';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;&lt;br /&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-414638958949686244?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/414638958949686244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=414638958949686244' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/414638958949686244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/414638958949686244'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/01/for-long-time-one-of-scores-of-software.html' title='You and your&apos;s sofware expansibility.'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-10892607549796023</id><published>2009-01-08T23:41:00.013+02:00</published><updated>2009-12-09T21:02:40.567+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tiles 2'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Freemarker'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Spring MVC  + FreeMarker + Tiles 2</title><content type='html'>This is extended and translated into English version of my post &lt;a href="http://java-ua.blogspot.com/2008/10/spring-mvc-freemarker-tiles-2.html"&gt;Spring MVC  + FreeMarker + Tiles 2&lt;/a&gt;. I've found that many are interested about the joint work of those frameworks. &lt;br /&gt;Well, this article shows how to configure the Spring MVC application with &lt;a href="http://tiles.apache.org"&gt;Tiles 2&lt;/a&gt; and &lt;a href="http://freemarker.org"&gt;FreeMarker&lt;/a&gt;. You may don't use the &lt;a href="http://springframework.org"&gt;SpringMVC&lt;/a&gt; framework, and in this case you need to make by your hands all the configuration work that Spring MVC does for you.&lt;br /&gt;As you may know, Freemarker is popular template engine write on Java and used by mostly by Java applications. Tiles 2 is also Java frameworks used to prepare document using one or more "tiles" - the parts that are defined separately but used to be generated at one document. For example, using tiles you can define site header/footer, news or post blocks at your site etc.&lt;br /&gt;So, how did I get it working?&lt;br /&gt;Simple!&lt;br /&gt;&lt;br /&gt;In file &lt;code&gt;web.xml&lt;/code&gt; add the freemarker configuration.&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;pages&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;pages&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;url-pattern&amp;gt;*.page&amp;lt;/url-pattern&amp;gt;&lt;br /&gt; &amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;freemarker&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;servlet-class&amp;gt;freemarker.ext.servlet.FreemarkerServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;init-param&amp;gt;&lt;br /&gt;            &amp;lt;param-name&amp;gt;TemplatePath&amp;lt;/param-name&amp;gt;&lt;br /&gt;            &amp;lt;param-value&amp;gt;/&amp;lt;/param-value&amp;gt;&lt;br /&gt;        &amp;lt;/init-param&amp;gt;&lt;br /&gt;        &amp;lt;init-param&amp;gt;&lt;br /&gt;            &amp;lt;param-name&amp;gt;NoCache&amp;lt;/param-name&amp;gt;&lt;br /&gt;            &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;&lt;br /&gt;        &amp;lt;/init-param&amp;gt;&lt;br /&gt;        &amp;lt;init-paramv&lt;br /&gt;            &amp;lt;param-name&amp;gt;ContentType&amp;lt;/param-name&amp;gt;&lt;br /&gt;            &amp;lt;param-value&amp;gt;text/html&amp;lt;/param-value&amp;gt;&lt;br /&gt;        &amp;lt;/init-param&amp;gt;&lt;br /&gt;&lt;br /&gt;        ....&lt;br /&gt;&lt;br /&gt;        &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;freemarker&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;url-pattern&amp;gt;*.ftl&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here is the important part *-servlet.xml configuration:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;!-- Tiles 2 configuration--&amp;gt;&lt;br /&gt;&amp;lt;bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"&amp;gt;&lt;br /&gt;        &amp;lt;property name="definitions"&amp;gt;&lt;br /&gt;            &amp;lt;list&amp;gt;&lt;br /&gt;                &amp;lt;!-- the tiles configuration files are declared here --&amp;gt; &lt;br /&gt;                &amp;lt;value&amp;gt;/WEB-INF/defs/general.xml&amp;lt;/value&amp;gt;&lt;br /&gt;                &amp;lt;value&amp;gt;/WEB-INF/defs/secure.xml&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;/list&amp;gt;&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="tilesViewResolver" class="com.javaua.spring.integration.ext.ExtUrlBasedViewResolver"&amp;gt;&lt;br /&gt;    &amp;lt;property name="viewClass" value="com.javaua.spring.integration.ext.ExtTilesView"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="exposeSpringMacroModel" value="true"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"&amp;gt;&lt;br /&gt;    &amp;lt;property name="cache" value="true"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="prefix" value=""/&amp;gt;&lt;br /&gt;    &amp;lt;property name="suffix" value=".ftl"/&amp;gt;&lt;br /&gt;    &amp;lt;!-- if you want to use the Spring FreeMarker macros, set this property to true --&amp;gt;&lt;br /&gt;    &amp;lt;property name="exposeSpringMacroHelpers" value="true"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Controller that returns view = /layout/header --&amp;gt;&lt;br /&gt;&amp;lt;bean name="/layout/header.page" class="com.javaua.HeaderController"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Also show here the part of general.xml file where Tiles definitions are set up.:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;definition name="home" extends="default"&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="title" value="Home Page"/&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="body" value="/templates/home.ftl"/&amp;gt;&lt;br /&gt;&amp;lt;/definition&amp;gt;&lt;br /&gt;&amp;lt;definition name="default" template="/templates/main.ftl"&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="header" value="/layout/header.page"/&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="footer" value="/templates/layout/footer.ftl"/&amp;gt;&lt;br /&gt;&amp;lt;/definition&amp;gt;&lt;br /&gt;&amp;lt;definition name="/layout/header" template="/templates/layout/header.ftl"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Source code of &lt;code&gt;com.javaua.spring.integration.ext.ExtUrlBasedViewResolver&lt;/code&gt; class:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import org.springframework.core.Ordered;&lt;br /&gt;import org.springframework.web.servlet.View;&lt;br /&gt;import org.springframework.web.servlet.view.AbstractUrlBasedView;&lt;br /&gt;import org.springframework.web.servlet.view.UrlBasedViewResolver;&lt;br /&gt;&lt;br /&gt;public class ExtUrlBasedViewResolver extends UrlBasedViewResolver implements Ordered {&lt;br /&gt;&lt;br /&gt;    private boolean exposeSpringMacroModel = false;&lt;br /&gt;&lt;br /&gt;    public void setExposeSpringMacroModel(boolean exposeSpringMacroModel) {&lt;br /&gt;        this.exposeSpringMacroModel = exposeSpringMacroModel;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected View loadView(String viewName, Locale locale) throws Exception {&lt;br /&gt;        AbstractUrlBasedView view = buildView(viewName);&lt;br /&gt;        View viewObj = (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);&lt;br /&gt;&lt;br /&gt;        if (viewObj instanceof ExtTilesView) {&lt;br /&gt;            ExtTilesView tilesView = (ExtTilesView) viewObj;&lt;br /&gt;            tilesView.setExposeSpringMacroModel(exposeSpringMacroModel);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return viewObj;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Source code of &lt;code&gt;com.javaua.spring.integration.ext.ExtTilesView&lt;/code&gt; class:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import org.springframework.web.servlet.view.tiles2.TilesView;&lt;br /&gt;import org.springframework.web.servlet.view.AbstractTemplateView;&lt;br /&gt;import org.springframework.web.servlet.support.RequestContext;&lt;br /&gt;&lt;br /&gt;import javax.servlet.http.HttpServletResponse;&lt;br /&gt;import javax.servlet.http.HttpServletRequest;&lt;br /&gt;import javax.servlet.ServletException;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class ExtTilesView extends TilesView {&lt;br /&gt;&lt;br /&gt;    private boolean exposeSpringMacroModel = false;&lt;br /&gt;&lt;br /&gt;    public void setExposeSpringMacroModel(boolean exposeSpringMacroModel) {&lt;br /&gt;        this.exposeSpringMacroModel = exposeSpringMacroModel;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings("unchecked")&lt;br /&gt;    protected final void renderMergedOutputModel(Map model, HttpServletRequest request,&lt;br /&gt;                                                 HttpServletResponse response) throws Exception {&lt;br /&gt;&lt;br /&gt;        if (exposeSpringMacroModel) {&lt;br /&gt;            if (model.containsKey(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE)) {&lt;br /&gt;                throw new ServletException(&lt;br /&gt;                        "Cannot expose bind macro helper '" +&lt;br /&gt;                        AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE +&lt;br /&gt;                        "' because of an existing model object of the same name");&lt;br /&gt;            }&lt;br /&gt;            model.put(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE,&lt;br /&gt;                    new RequestContext(request, getServletContext(), model));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        super.renderMergedOutputModel(model, request, response);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Why we need those two classes? Simple enough. Class &lt;code&gt;ExtTilesView&lt;/code&gt; exposes Spring macro model which is required when using standard macros used to support work with Freemarker and Velocity typelate frameworks. And the class &lt;code&gt;ExtUrlBasedViewResolver&lt;/code&gt; helps us to prevent view-not-found-error. Because, standard &lt;code&gt;UrlBasedViewResolver&lt;/code&gt; is used for getting tiles view, it will throw an error when view with specified name is not found. In my case, I have two view resolvers and each will throw an error if view can't be found. &lt;br /&gt;And &lt;code&gt;FreeMarkerViewResolver&lt;/code&gt; will request for the file, while tiles requests just for XML definition. That's why I've ran the tiles view resolver as first one.&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://java-ua.blogspot.com/2009/01/spring-mvc-freemarker-tiles-2.html';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Spring MVC + FreeMarker + Tiles 2';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;&lt;br /&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-10892607549796023?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/10892607549796023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=10892607549796023' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/10892607549796023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/10892607549796023'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/01/spring-mvc-freemarker-tiles-2.html' title='Spring MVC  + FreeMarker + Tiles 2'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6750535230419390619</id><published>2009-01-08T23:08:00.006+02:00</published><updated>2009-01-09T00:03:48.399+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Intellij Idea'/><category scheme='http://www.blogger.com/atom/ns#' term='JVM'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>GC and performance</title><content type='html'>&lt;p&gt;Мабуть, нікому не секрет, що GC є дуже важливою річчю в JVM, і що вона займається звільненням памяті, що вже не використовуються. Також багатьом відомо, що є кілька різних політик виконання очистки пам'яті. Конфігурація не виглядає надто складною, є всього кілька можливих варіантів вибору політики GC:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;SerialGC - встановлена по дефолту, працює найкраще якщо на машині тільки один процесор, коли виконуєть збір сміття, то програма тормозить, адже в даний момент вона не відповідає.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ParallelGC - використовується можливість виконувати мінорний (minor) збір сміття в паралельних потоках. Програма здатна відповідати на запити клієнта в момент збору сміття&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ParallelOldGC - виконує мажорний (major) збір сміття в паралельних потоках&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ConcMarkSweepGC - В даному випадку постійно відбувається збір сміття, програма не тормозить при зборах сміття, як це можна замітити в 3 попередніх випадках.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Таким чином, я вирішив переконфігурувати для прикладу &lt;a href="http://jetbrains.com/idea"&gt;IntellijIdea&lt;/a&gt;, що я використовую. &lt;br /&gt;&lt;code&gt;&lt;br /&gt;-Xms256m&lt;br /&gt;-Xmx512m&lt;br /&gt;&lt;b&gt;-XX:MaxPermSize=120m&lt;/b&gt;&lt;br /&gt;-XX:+UseConcMarkSweepGC&lt;br /&gt;-ea&lt;br /&gt;-Dawt.useSystemAAFontSettings=lcd&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Для покращення швидкодії роботи, можна також установити значення ms = mx, так щоб&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;b&gt;-Xms512m&lt;/b&gt;&lt;br /&gt;-Xmx512m&lt;br /&gt;-XX:MaxPermSize=120m&lt;br /&gt;-XX:+UseConcMarkSweepGC&lt;br /&gt;-ea&lt;br /&gt;-Dawt.useSystemAAFontSettings=lcd&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Ресурси&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html"&gt;Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning&lt;/a&gt; - із серії must-read&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp"&gt;Java HotSpot VM Options&lt;/a&gt; - якось давно шукав подібну документацію, тепер повезло більше - знашов.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.petefreitag.com/articles/gctuning/"&gt;Tuning Garbage Collection Outline&lt;/a&gt; - цікава підбірка фактів про GC&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6750535230419390619?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6750535230419390619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6750535230419390619' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6750535230419390619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6750535230419390619'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2009/01/gc-and-performance.html' title='GC and performance'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-5664776677444491967</id><published>2008-12-25T17:32:00.005+02:00</published><updated>2008-12-25T17:44:28.751+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Java Enums та перевизначення методів</title><content type='html'>Читаючи книгу &lt;a href="http://www.pragprog.com/titles/vslg/programming-groovy"&gt;Programming Groovy&lt;/a&gt;, я дізнався про можливість перевизначати методи в enums. Про це навіть не здогадувався раніше, і це мене справді здивувало.&lt;br /&gt;І справді, нехай у нас є &lt;code&gt;enum&lt;/code&gt; в якому вказані дні в тижні:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;enum DAYS {&lt;br /&gt;  MON, TUE,&lt;br /&gt;  WED, THU, &lt;br /&gt;  FRI, SAT, &lt;br /&gt;  SUN;&lt;br /&gt;&lt;br /&gt;  public String is() {&lt;br /&gt;     return "working";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Що ж, &lt;code&gt;MON.is().equals("working")&lt;/code&gt; має бути істинним; але подібне тяжко сказати, наприклад, для &lt;code&gt;SUN.is().equals("working")&lt;/code&gt;. &lt;br /&gt;Звичайно тепер ми можемо визначити &lt;code&gt;enum&lt;/code&gt; наступним чином:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;enum DAYS {&lt;br /&gt;  MON, TUE,&lt;br /&gt;  WED, THU, &lt;br /&gt;  FRI, &lt;br /&gt;  SAT {&lt;br /&gt;     public String is() {&lt;br /&gt;        return "week-end, day 1";&lt;br /&gt;     }&lt;br /&gt;  },&lt;br /&gt;  SUN {&lt;br /&gt;     public String is() {&lt;br /&gt;        return "week-end, day 2";&lt;br /&gt;     }&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  public String is() {&lt;br /&gt;     return "working";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;І все, тепер &lt;code&gt;SUN.is().equals("week-end, day 2") == true&lt;/code&gt;.&lt;br /&gt;Проблема вирішена, при чому, без збереження зайвого поля - вказівника на рядок.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-5664776677444491967?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/5664776677444491967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=5664776677444491967' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5664776677444491967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/5664776677444491967'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/12/java-enums.html' title='Java Enums та перевизначення методів'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1018675035490799374</id><published>2008-12-15T03:18:00.004+02:00</published><updated>2008-12-15T20:16:06.517+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><title type='text'>Mac OS X</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;Still, If I'll not find the solution with java update and sound bad work then I'll become Linux (Ubuntu) user.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1018675035490799374?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1018675035490799374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1018675035490799374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1018675035490799374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1018675035490799374'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/12/mac-os-x.html' title='Mac OS X'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4315745528998984968</id><published>2008-10-27T23:27:00.002+02:00</published><updated>2008-12-08T04:46:40.586+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Google App Engine &amp; Java</title><content type='html'>Google нарешті таки вирішив, що наступна версія App Engine буде підтримувати Java. З самого початку пора. А ще би було добре позбутися декотрих дивних обмежень, як от, тривалість запиту, маскимальний розмір файлу тощо.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4315745528998984968?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4315745528998984968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4315745528998984968' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4315745528998984968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4315745528998984968'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/10/google-app-engine-java.html' title='Google App Engine &amp; Java'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-6818889161344766810</id><published>2008-10-27T22:20:00.012+02:00</published><updated>2008-10-27T23:12:32.299+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JVM'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>SoftReference &amp; WeakReference: time of life</title><content type='html'>Well, I found some free time to write few articles. This one is about the &lt;code&gt;SoftReference&lt;/code&gt; class from Java library. &lt;br /&gt;&lt;code&gt;SoftReference&lt;/code&gt; 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.&lt;br /&gt;More about this. First I set &lt;code&gt;-verbose:gc&lt;/code&gt; parameter for Java machine. If this parameter is set than GC logs will be output to the console. Also was set parameter &lt;code&gt;-Xmx32m&lt;/code&gt;. The simple code:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;void test() {&lt;br /&gt;    Reference&amp;lt;List&amp;gt; listRef = new SoftReference&amp;lt;List&amp;gt;(&lt;br /&gt;               Arrays.asList("1", "2", "3", "4", "5"));&lt;br /&gt;&lt;br /&gt;    List list = new LinkedList();&lt;br /&gt;    for (int i = 1; i &amp;lt;= 5; i++) {&lt;br /&gt;       list.add(new Object());&lt;br /&gt;&lt;br /&gt;       if (i == 5) {&lt;br /&gt;           if (listRef.get() == null) {&lt;br /&gt;                break;&lt;br /&gt;           }&lt;br /&gt;           i = 1;&lt;br /&gt;       }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[GC 896K-&gt;708K(5056K), 0.0059887 secs]&lt;br /&gt;[GC 1604K-&gt;1603K(5056K), 0.0064902 secs]&lt;br /&gt;[GC 2499K-&gt;2498K(5056K), 0.0064698 secs]&lt;br /&gt;[GC 3394K-&gt;3393K(5056K), 0.0062198 secs]&lt;br /&gt;[GC 4289K-&gt;4287K(5184K), 0.0061248 secs]&lt;br /&gt;[Full GC 4287K-&gt;4287K(5184K), 0.0378679 secs]&lt;br /&gt;[GC 5120K-&gt;5119K(8000K), 0.0141557 secs]&lt;br /&gt;[GC 6015K-&gt;6014K(8000K), 0.0069241 secs]&lt;br /&gt;[GC 6910K-&gt;6908K(8000K), 0.0064464 secs]&lt;br /&gt;[GC 7804K-&gt;7804K(8768K), 0.0061396 secs]&lt;br /&gt;[Full GC 7804K-&gt;7804K(8768K), 0.0595140 secs]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;We may see that more than one Full GC were run before the soft reference was cleaned up.&lt;br /&gt;The same test for the WeakReference (change &lt;code&gt;new SoftReference&lt;List&gt;(...)&lt;/code&gt; into &lt;code&gt;new WeakReference&lt;List&gt;(...)&lt;/code&gt;) prints next output:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[GC 896K-&gt;707K(5056K), 0.0063061 secs]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;So, weak reference is cleaned up after the next first GC runs. &lt;br /&gt;These tests were made on Java 1.6.0_10.&lt;br /&gt;The outputs for Java 1.5.0_07 are respectively&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[GC 512K-&gt;387K(1984K), 0.0047419 secs]&lt;br /&gt;[GC 899K-&gt;898K(1984K), 0.0046456 secs]&lt;br /&gt;[GC 1410K-&gt;1409K(1984K), 0.0048894 secs]&lt;br /&gt;[GC 1921K-&gt;1920K(2496K), 0.0046743 secs]&lt;br /&gt;[Full GC 1920K-&gt;1920K(2496K), 0.0203305 secs]&lt;br /&gt;[GC 2431K-&gt;2430K(3776K), 0.0103943 secs]&lt;br /&gt;[GC 2942K-&gt;2941K(3776K), 0.0048556 secs]&lt;br /&gt;[GC 3453K-&gt;3452K(4032K), 0.0047855 secs]&lt;br /&gt;[Full GC 3452K-&gt;3452K(4032K), 0.0340532 secs]&lt;br /&gt;[GC 3964K-&gt;3963K(6332K), 0.0044411 secs]&lt;br /&gt;[GC 4475K-&gt;4474K(6332K), 0.0049126 secs]&lt;br /&gt;[GC 4986K-&gt;4985K(6332K), 0.0046232 secs]&lt;br /&gt;[GC 5497K-&gt;5496K(6332K), 0.0045682 secs]&lt;br /&gt;[GC 6008K-&gt;6007K(6588K), 0.0047892 secs]&lt;br /&gt;[Full GC 6007K-&gt;6007K(6588K), 0.0523812 secs]&lt;br /&gt;[GC 6775K-&gt;6774K(10848K), 0.0061404 secs]&lt;br /&gt;[GC 7542K-&gt;7540K(10848K), 0.0065743 secs]&lt;br /&gt;[GC 8308K-&gt;8307K(10848K), 0.0067296 secs]&lt;br /&gt;[GC 9075K-&gt;9074K(10848K), 0.0066386 secs]&lt;br /&gt;[GC 9842K-&gt;9841K(10848K), 0.0066439 secs]&lt;br /&gt;[GC 10609K-&gt;10608K(11488K), 0.0066955 secs]&lt;br /&gt;[Full GC 10608K-&gt;10606K(11488K), 0.1112694 secs]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;and &lt;br /&gt;&lt;code&gt;&lt;br /&gt;[GC 512K-&gt;387K(1984K), 0.0049869 secs]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-6818889161344766810?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/6818889161344766810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=6818889161344766810' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6818889161344766810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/6818889161344766810'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/10/softreference-weakreference-time-of.html' title='SoftReference &amp; WeakReference: time of life'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8273158281318181721</id><published>2008-10-27T21:16:00.010+02:00</published><updated>2009-01-08T23:42:46.691+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Spring MVC + FreeMarker + Tiles 2</title><content type='html'>Може комусь і знадобиться ще. Тут описується як прикрутити &lt;a href="http://springframework.org"&gt;Spring MVC&lt;/a&gt; та &lt;a href="http://freemarker.org"&gt;FreeMarker&lt;/a&gt; та &lt;a href="http://tiles.apache.org"&gt;Tiles 2&lt;/a&gt; так, щоб вони жили та працювали разом. &lt;br /&gt;Задача: Tiles2 повинен організовувати шаблони створені на основі FreeMarker (хоча можна і не тільки FreeMarker, можна поєднувати). Для того, щоб досягнути це необхідно виконати декотру конфігурацію. У файлі &lt;code&gt;web.xml&lt;/code&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;pages&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;pages&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;url-pattern&amp;gt;*.page&amp;lt;/url-pattern&amp;gt;&lt;br /&gt; &amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;freemarker&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;servlet-class&amp;gt;freemarker.ext.servlet.FreemarkerServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;init-param&amp;gt;&lt;br /&gt;            &amp;lt;param-name&amp;gt;TemplatePath&amp;lt;/param-name&amp;gt;&lt;br /&gt;            &amp;lt;param-value&amp;gt;/&amp;lt;/param-value&amp;gt;&lt;br /&gt;        &amp;lt;/init-param&amp;gt;&lt;br /&gt;        &amp;lt;init-param&amp;gt;&lt;br /&gt;            &amp;lt;param-name&amp;gt;NoCache&amp;lt;/param-name&amp;gt;&lt;br /&gt;            &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;&lt;br /&gt;        &amp;lt;/init-param&amp;gt;&lt;br /&gt;        &amp;lt;init-paramv&lt;br /&gt;            &amp;lt;param-name&amp;gt;ContentType&amp;lt;/param-name&amp;gt;&lt;br /&gt;            &amp;lt;param-value&amp;gt;text/html&amp;lt;/param-value&amp;gt;&lt;br /&gt;        &amp;lt;/init-param&amp;gt;&lt;br /&gt;&lt;br /&gt;        ....&lt;br /&gt;&lt;br /&gt;        &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;freemarker&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;url-pattern&amp;gt;*.ftl&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А тепер конфігурація pages-servlet.xml:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;!-- Конфігурація Tiles --&amp;gt;&lt;br /&gt;&amp;lt;bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"&amp;gt;&lt;br /&gt;        &amp;lt;property name="definitions"&amp;gt;&lt;br /&gt;            &amp;lt;list&amp;gt;&lt;br /&gt;                &amp;lt;value&amp;gt;/WEB-INF/defs/general.xml&amp;lt;/value&amp;gt;&lt;br /&gt;                &amp;lt;value&amp;gt;/WEB-INF/defs/secure.xml&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;/list&amp;gt;&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"&amp;gt;&lt;br /&gt;        &amp;lt;property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Контролер повертає view = /layout/header --&amp;gt;&lt;br /&gt;&amp;lt;bean name="/layout/header.page" class="au.com.at2.web.spring.HeaderController"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Частина файла general.xml, в якому описуються оголошення Tiles:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;definition name="home" extends="default"&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="title" value="Home Page"/&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="body" value="/templates/home.ftl"/&amp;gt;&lt;br /&gt;&amp;lt;/definition&amp;gt;&lt;br /&gt;&amp;lt;definition name="default" template="/templates/main.ftl"&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="header" value="/layout/header.page"/&amp;gt;&lt;br /&gt;        &amp;lt;put-attribute name="footer" value="/templates/layout/footer.ftl"/&amp;gt;&lt;br /&gt;&amp;lt;/definition&amp;gt;&lt;br /&gt;&amp;lt;definition name="/layout/header" template="/templates/layout/header.ftl"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Невеличке пояснення:&lt;br /&gt;Спочатку добавив новий сервлет для FreeMarker'а. Всі шаблони в мене наразі стоять в каталозі &lt;code&gt;templates&lt;/code&gt;, в той час, як &lt;code&gt;TemplatePath&lt;/code&gt; для FreeMarker'а - це /. Я це зробив собі на майбутнє - для добавлення нових каталогів крім templates, - адже аплікація має розширюватися (вони завжди розширюються).&lt;br /&gt;В &lt;code&gt;pages-servlet.xml&lt;/code&gt; добавив bean &lt;code&gt;tilesConfigurer&lt;/code&gt;, який будує конфігурацію для Tiles. Оголошення же знаходяться у файлах &lt;code&gt;/WEB-INF/defs/general.xml, /WEB-INF/defs/secure.xml&lt;/code&gt;. При конфігурації інформація із них мерджеться, отже, оголошення &lt;code&gt;default&lt;/code&gt; є доступним і в межах &lt;code&gt;secure.xml&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;put-attribute name="header" value="/layout/header.page"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Цей кусок значить - можна використовувати як тайл і сторінку, що обробляється &lt;code&gt;DispatcherServlet&lt;/code&gt;, таким чинном, ми можемо мати окремі контролери для окреми тайлів. І це правильно. Без цього би було туго. Контролер &lt;code&gt;au.com.at2.web.spring.HeaderController&lt;/code&gt; повертає view &lt;code&gt;/layout/header&lt;/code&gt;, який оголошений як definition в &lt;code&gt;general.xml&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8273158281318181721?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8273158281318181721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8273158281318181721' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8273158281318181721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8273158281318181721'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/10/spring-mvc-freemarker-tiles-2.html' title='Spring MVC + FreeMarker + Tiles 2'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-2386855557501492828</id><published>2008-10-08T02:10:00.011+03:00</published><updated>2009-03-16T16:16:06.506+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Portlet'/><category scheme='http://www.blogger.com/atom/ns#' term='RichFaces'/><title type='text'>RichFaces + JSF RI + JBossPortletBridge + Liferay Portal on JBoss AS 4.2.x</title><content type='html'>The task to make few portlets for &lt;a href="http://liferay.com"&gt;Liferay 5.1 Portal&lt;/a&gt; using &lt;a href="http://www.jboss.org/jbossrichfaces/"&gt;RichFaces&lt;/a&gt; + &lt;a href="https://javaserverfaces.dev.java.net/"&gt;JSF RI&lt;/a&gt; looks trivial. But it isn't. &lt;br /&gt;There are few decisions:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Use Liferay listener for Sun JSF with Sun's FacesPortlet.&lt;br /&gt;&lt;li&gt;Use JBossPortletBridge, because it supports RichFaces and AJAX.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;I choosed the second with understanding that &lt;a href="http://www.jboss.org/portletbridge/"&gt;JBossPortletBridge&lt;/a&gt; is in beta and everywhere says that it supports JBossPortal, but I did not find where says - "It supports Liferay too". &lt;b&gt;It does not support Liferay Portal 5.0&lt;/b&gt;.&lt;br /&gt;I found few interesting things, that anyone should know before starting write portlets with RichFaces for Liferay using JBossPortletBridge 1.0.x Beta:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;RichFaces should be at least 3.2.1.&lt;br /&gt;&lt;li&gt;You should configure portlet as ajaxable with server side state saving policy&lt;br /&gt;&lt;li&gt;Override the &lt;code&gt;javax.portlet.faces.GenericFacesPortlet&lt;/code&gt; given with JBossPortletBridge. You'll need manually setup the request attribute &lt;code&gt;javax.servlet.include.path_info&lt;/code&gt; with correct viewId you want to process and render. Or you can setup this request attribute at the &lt;code&gt;PortletExternalContextImpl&lt;/code&gt; class in &lt;code&gt;calculateServletPath()&lt;/code&gt; method (remember JBossPortletBridge 1.0.x Beta). &lt;br /&gt;&lt;li&gt;Use &lt;code&gt;&amp;lt;a4j:commandXXX/&amp;gt;&lt;/code&gt; components to process navigation. &lt;code&gt;&amp;lt;h:commandXXX/&amp;gt;&lt;/code&gt; will not help ((.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Good luck!&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;Update:&lt;br /&gt;My friend Andriy has described the solution with details and configuration samples, and you can find his post by the url &lt;a href="http://www.liferay.com/web/guest/community/forums/-/message_boards/message/1712557"&gt;http://www.liferay.com/web/guest/community/forums/-/message_boards/message/1712557&lt;/a&gt;. It really can be useful for you.&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;I've uploaded the portlet sample prototype, so it's ready and waits for you :)&lt;br /&gt;&lt;a href="http://www.esnips.com/doc/de8b5661-fb6d-4fc7-83a3-ed09aa72c695/PortletPrototype"&gt;http://www.esnips.com/doc/de8b5661-fb6d-4fc7-83a3-ed09aa72c695/PortletPrototype&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-2386855557501492828?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/2386855557501492828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=2386855557501492828' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2386855557501492828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2386855557501492828'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/10/richfaces-jsf-ri-jbossportletbridge.html' title='RichFaces + JSF RI + JBossPortletBridge + Liferay Portal on JBoss AS 4.2.x'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-3256326576422686169</id><published>2008-10-03T12:49:00.011+03:00</published><updated>2008-10-03T19:25:45.566+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Java 7</title><content type='html'>&lt;p&gt;Java 7 в процесі написання. Цікаво знати які саме зміни мають попасти в реліз Java7. &lt;a href="http://tech.puredanger.com/java7"&gt;Тут&lt;/a&gt; можна знайти, що саме &lt;a href="http://tech.puredanger.com/java7"&gt;планувалося в реліз Java 7&lt;/a&gt; , а ось &lt;a href="http://tech.puredanger.com/2008/08/02/java7-prediction-update/"&gt;тут - статус нових фіч станом на початок серпня&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Нажаль, closures - далекі від готовності, і зважаючи, що Ніл Гафтер покинув Google і перейшов працювати в Microsoft, є ризик, що closures не увійдуть до Java7. Проте є всі шанси, що switch для рядків, порівняння enum'ів попадуть в реліз. Але от підтримка операторів +, -, *, /, % для &lt;code&gt;BigDecimal&lt;/code&gt; - ще далекі від кінця. Хоча це мені видається не менш важливим, ніж інші нововедення.&lt;/p&gt;&lt;p&gt;Для тих, хто не раз відчував дискомфорт при роботі із generics в Java - слід звернути увагу на &lt;a href="http://tech.puredanger.com/java7#typeliterals"&gt;type literals&lt;/a&gt; і &lt;a href="http://tech.puredanger.com/java7#typeinference"&gt;type inference&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href="http://tech.puredanger.com/java7#invokedynamic"&gt;Invokedynamic&lt;/a&gt; - потрібний для підтримки динамічних мов.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-3256326576422686169?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/3256326576422686169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=3256326576422686169' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3256326576422686169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3256326576422686169'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/10/java-7.html' title='Java 7'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8339058378126318058</id><published>2008-09-26T01:24:00.006+03:00</published><updated>2008-09-26T01:28:29.018+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>String.length(): підводні камні</title><content type='html'>&lt;p&gt;&lt;br /&gt;Як виявилося, не завжди &lt;code&gt;length()&lt;/code&gt; повертає дійсну кількість символів у рядку. В класі &lt;code&gt;String&lt;/code&gt; чимало підводних камнів та різної недокінця вірної поведінки. Одна із них стосується того, як правильно рахувати кількість символів у рядку. &lt;br /&gt;&lt;a href="http://java.sun.com/mailers/techtips/corejava/2006/tt0822.html"&gt;Тут більше про це...&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8339058378126318058?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8339058378126318058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8339058378126318058' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8339058378126318058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8339058378126318058'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/09/stringlength.html' title='String.length(): підводні камні'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-9167770661758573103</id><published>2008-08-25T10:07:00.003+03:00</published><updated>2008-08-25T10:13:40.818+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>How to throw unexpected checked exceptions</title><content type='html'>Today I found that it is possible to throw checked exceptions even if they are not declared in &lt;code&gt;throws&lt;/code&gt; section.&lt;br /&gt;What did we do when we have need to throw some checked exception? We do:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public void doSomething() throws CannotDoSomethingException {&lt;br /&gt;    throw new CannotDoSomethingException();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class CannotDoSomethingException extends Exception {&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But we can to throw the checked exception without declaring it at throws section:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public void doSomething() {&lt;br /&gt;    Thread.currenThread().stop(new CannotDoSomethingException());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I think that this is veeeery bad code&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-9167770661758573103?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/9167770661758573103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=9167770661758573103' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/9167770661758573103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/9167770661758573103'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/08/how-to-throw-unexpected-checked.html' title='How to throw unexpected checked exceptions'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8538371285490420079</id><published>2008-08-06T00:20:00.004+03:00</published><updated>2008-08-06T00:30:22.383+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>java.lang.String.concat()</title><content type='html'>Світ класу &lt;code&gt;java.lang.String&lt;/code&gt; є чималим. Багато речей заховано глибоко і далеко, чимало просто плавають на верху, але ми їх не завжди бачимо.&lt;br/&gt;&lt;br /&gt;Так, наприклад, метод &lt;code&gt;concat()&lt;/code&gt; приймає рядок і повертає рядок, який є конкатенацією даного рядка і переданого у вигляді параметра. Рядок-параметр добавляється в кінець даного рядка. Існує, щоправда, виключення, а саме: якщо рядок-параметр є пустим (себто, &lt;code&gt;""&lt;/code&gt;), то тоді метод &lt;code&gt;concat()&lt;/code&gt; повертає дану стрічку. В даному випадку економиться час на виконання операції конкатенації для двух рядків. Це є перша відмінність від використання оператора конкатенації рядків "+". &lt;br /&gt;&lt;br/&gt;Іншою різницею є те, що якщо рядок-параметр є &lt;code&gt;null&lt;/code&gt;, то тоді &lt;code&gt;java.lang.NullPointerException&lt;/code&gt; виникає. У випадку ж з "+", &lt;code&gt;null&lt;/code&gt; буде замінено на рядок &lt;code&gt;"null"&lt;/code&gt;, оскільки, &lt;code&gt;String.valueOf(null)&lt;/code&gt; повертає &lt;code&gt;"null"&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8538371285490420079?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8538371285490420079/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8538371285490420079' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8538371285490420079'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8538371285490420079'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/08/javalangstring.html' title='java.lang.String.concat()'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7222751361623766001</id><published>2008-08-05T23:34:00.013+03:00</published><updated>2008-10-31T00:27:21.790+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Assertions</title><content type='html'>Well, one of the most usable feature of safe codding is assertions.&lt;br /&gt;Assertions help to prevent executing code with usafe or unchecked data, for example, with &lt;code&gt;null&lt;/code&gt; or wrong parameters, empty strings, too long strings, empty arrays or lists can be unforeseen arguments and must be checked before using.&lt;/br&gt;&lt;br /&gt;You may remember the asserts from &lt;a href="http://junit.org"&gt;JUnit&lt;/a&gt;. Remember:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;assertNotFalse(a &gt; 5, "a cannot be equal or less then 5");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Well, in &lt;a href="http://commons.apache.org/lang/"&gt;Apache Commons Lang&lt;/a&gt; library you may use the &lt;code&gt;org.apache.commons.lang.Validate&lt;/code&gt; class to validate arguments or state in your code. You may use it next:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;void saveEntity(Entity entity) {&lt;br /&gt;    Validate.notNull(entity);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then, if entity value is then &lt;code&gt;java.lang.IllegalArgumentException&lt;/code&gt; is thrown. In other case next code is executed.&lt;br/&gt;&lt;br /&gt;There is also overloaded version of such assert methods in &lt;code&gt;Validate&lt;/code&gt; class or in JUnit, that helps to describe the assertion:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;void saveEntity(Entity entity) {&lt;br /&gt;    Validate.notNull(entity, "Entity cannot be null.");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I am the fun of the overloaded version of assert methods. Truly say, I think that only version with string description of assertion has right to live. That helps developers to find the source of problem quickly and also it may be used to process the errors.&lt;br /&gt;The other point is to have assert-liked-validation also for state, that will throw the &lt;code&gt;java.lang.IllegalStateException&lt;/code&gt;. This type of assertion should used for checking the result of calculation or processing, but not for arguments. So we could have something like:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;void saveEntity(Entity entity) {&lt;br /&gt;     ArgumentAssert.isNotNull(entity, "Entity cannot be null.");&lt;br /&gt;&lt;br /&gt;     // create or update the entity,&lt;br /&gt;     // then returns entity id, that must be not null value if everything is OK&lt;br /&gt;     Integer entityId = dao.save(entity); &lt;br /&gt;&lt;br /&gt;     StateAssert.isNotNull(entityId, "Entity is not saved, because entity id is null.");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The code is not the best, but this shows how &lt;code&gt;StateAssert&lt;/code&gt; should be used.&lt;br /&gt;&lt;br /&gt;So, if the &lt;code&gt;entityId&lt;/code&gt; is null, then &lt;code&gt;StateAssert.isNotNull()&lt;/code&gt; method throws &lt;code&gt;IllegalStateException&lt;/code&gt;. Before that, &lt;code&gt;ArgumentAssert.isNotNull()&lt;/code&gt; method checks whether &lt;code&gt;entity&lt;/code&gt; is not null and throws &lt;code&gt;IllegalArgumentException&lt;/code&gt; if it is.&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;And every assert methods, should check whether assertions are enabled, for example, by using system properties.&lt;br/&gt;&lt;br /&gt;And what about &lt;code&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/code&gt; statement in Java? &lt;br /&gt;It should be used, but one type of assertions support must be choosed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7222751361623766001?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7222751361623766001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7222751361623766001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7222751361623766001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7222751361623766001'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/08/assertions.html' title='Assertions'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-956700374390638992</id><published>2008-07-28T13:12:00.017+03:00</published><updated>2009-10-12T19:12:33.423+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><title type='text'>Build Flex with ANT</title><content type='html'>Ця стаття про виконання білда простої &lt;a href="http://www.adobe.com/products/flex/"&gt;Flex&lt;/a&gt; аплікації із використанням &lt;a href="http://ant.apache.org/"&gt;ANT&lt;/a&gt;.&lt;br/&gt;&lt;br /&gt;Мабуть, для того щоб виконати білд простої Flex аплікації слід знати тільки два тарґети:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://livedocs.adobe.com/flex/3/html/help.html?content=anttasks_5.html#207493"&gt;&lt;code&gt;mxmlc&lt;/code&gt;&lt;/a&gt; -  білд mxml у swf файл.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://livedocs.adobe.com/flex/3/html/help.html?content=anttasks_7.html#207598"&gt;&lt;code&gt;html-wrapper&lt;/code&gt;&lt;/a&gt; - побудова hmtl файлів обгорток для результуючого swf файла.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Нехай, &lt;code&gt;FLEX_HOME&lt;/code&gt; - вказує на шлях, де знаходиться на диску сам Flex, тоді, можна підключити в ANT скріпті&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Тоді, для того, щоб збілдити swf'ку слід виконати наступний антівський скрипт:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt; &amp;lt;mxmlc file="${flexApps.basedir}/src/EventsView.mxml"&lt;br /&gt;           context-root="/WebAppContext"&lt;br /&gt;           keep-generated-actionscript="true"&lt;br /&gt;           services="${webapp.basedir}/WebContent/WEB-INF/flex/services-config.xml"&lt;br /&gt;           output="${flexApps.output.dir}/EventsView.swf"&amp;gt;&lt;br /&gt;       &amp;lt;compiler.library-path dir="${FLEX_HOME}/frameworks" append="true"&amp;gt;&lt;br /&gt;            &amp;lt;include name="${ipcom.basedir}/WebContent/WEB-INF/lib/"/&amp;gt;&lt;br /&gt;       &amp;lt;/compiler.library-path&amp;gt;&lt;br /&gt;       &amp;lt;load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/&amp;gt;&lt;br /&gt;       &amp;lt;source-path path-element="${FLEX_HOME}/frameworks"/&amp;gt;&lt;br /&gt; &amp;lt;/mxmlc&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Отже, що собою являють атрибути:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;file&lt;/code&gt; - файл mxml, який представляє собою флекс-аплікацію&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;context-root&lt;/code&gt; - назва контексту веб-аплікації, яка використовуватиметься для загрузки флек-аплікаціїю&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;services&lt;/code&gt; - файл із описаними сервісами.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;output&lt;/code&gt; - шлях і назва результуючого файла.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;А щоб згенерити обгортки:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;html-wrapper file="EventsView.html"&lt;br /&gt;                 history="true"&lt;br /&gt;                 template="express-installation"&lt;br /&gt;                 application="EventsView"&lt;br /&gt;                 title="Flex Events Viewer"&lt;br /&gt;                 width="600" height="400"                &lt;br /&gt;                 output="${flexApps.output.dir}"&lt;br /&gt;                 swf="EventsView"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-956700374390638992?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/956700374390638992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=956700374390638992' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/956700374390638992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/956700374390638992'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/07/build-flex-with-ant.html' title='Build Flex with ANT'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4925627021894995468</id><published>2008-07-26T22:52:00.011+03:00</published><updated>2008-07-28T13:11:57.521+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='FP'/><title type='text'>Функціональне програмування</title><content type='html'>Мабуть важко не замітити, якої потуги набирає &lt;a href="http://uk.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D1%96%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D1%83%D0%B2%D0%B0%D0%BD%D0%BD%D1%8F"&gt;функціональне програмування&lt;/a&gt; останнім часом. І тому є декілька поважних причин, а саме:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;використання функціональних мов програмування для написання програм, що використовують конкурентність; іншими словами фукнціональні мови програмування дозволяють писати програми, що можуть працювати і використовувати всі можливості сьогоднішніх багатоядерних процесорів;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;гнучкісь функціональних мов програмування просто вражає;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;написання програм за допомогою функціональних мов є досить нескладним, адже вони беруть основу з математичного визначення &lt;a href="http://en.wikipedia.org/wiki/Function_(mathematics)"&gt;функції&lt;/a&gt;;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;декотрі функціональні мови програмування (наприклад, &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;) дозволяє використовувати аспекти об'єктно-орієнтованого програмування.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Доречі, від &lt;a href="http://commons.apache.org/"&gt;Apache Commons&lt;/a&gt; є бібліотека &lt;a href="http://commons.apache.org/sandbox/functor/"&gt;Functor&lt;/a&gt;, яка дозволяє використати деякі елементи функціонального програмування в Java. Нажаль, бібліотека ще не в релізі, але будемо надіятися це не надовго. Ця бібліотека дозволить використати такі корисні речі як 1) функції вищого порядку, 2) фільтри, 3) callback функції тощо.&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;Більш детальнішу інформацію можна знайти там:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.ibm.com/developerworks/java/library/j-fp.html"&gt;Functional programming in the Java language&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/w/index.php?title=Functional_programming"&gt;Functional programming&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://homepages.inf.ed.ac.uk/wadler/realworld/"&gt;Functional Programming in the Real World&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4925627021894995468?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4925627021894995468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4925627021894995468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4925627021894995468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4925627021894995468'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/07/blog-post.html' title='Функціональне програмування'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8770419821337019857</id><published>2008-06-26T19:02:00.009+03:00</published><updated>2008-07-02T19:25:48.468+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Правила "Не забудь!"</title><content type='html'>&lt;ol&gt;&lt;br /&gt;&lt;li&gt;при добавленні нових полів до класу звернути увагу на методи hashCode(), equals() та compareTo(), - може слід добавити і туди обробку нового поля&lt;/li&gt;&lt;br /&gt;&lt;li&gt;при добавленні поля типу колекції, - надати їй початкове значення&lt;/li&gt;&lt;br /&gt;&lt;li&gt;перечитати той код, що ти написав&lt;/li&gt;&lt;br /&gt;&lt;li&gt;протестувати те, що ти закодував чи перекодував&lt;/li&gt;&lt;br /&gt;&lt;li&gt;може це можна було зробити по інакшому? якщо так, то як? а чим воно краще?&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8770419821337019857?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8770419821337019857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8770419821337019857' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8770419821337019857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8770419821337019857'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/06/blog-post_26.html' title='Правила &quot;Не забудь!&quot;'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8839130492676031660</id><published>2008-06-23T03:49:00.003+03:00</published><updated>2008-06-23T03:57:07.067+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Java call stack for simple web application</title><content type='html'>Interesting to see the call stack of simple action on web application written on Java, isn't it?&lt;br /&gt;I found the blog story with picture of call stack from HTTP to JDBC. &lt;a href="http://ptrthomas.wordpress.com/2006/06/06/java-call-stack-from-http-upto-jdbc-as-a-picture/"&gt;Here it is.&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It is beautiful. A long path and only two calls to the application business and DAO methods. Comments are very interesting too.&lt;br /&gt;They are from PHP developers, from administrators etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8839130492676031660?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8839130492676031660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8839130492676031660' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8839130492676031660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8839130492676031660'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/06/java-call-stack-for-simple-web.html' title='Java call stack for simple web application'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-53618351909278798</id><published>2008-06-22T22:07:00.003+03:00</published><updated>2008-06-23T03:47:44.086+03:00</updated><title type='text'>Зміни в блозі</title><content type='html'>В результаті вивчення суті блогів, статистики блогу та власних побажань, я міняю суть даного блога із суто джавового на суто компютерний із основною орієнтацією на джаву.&lt;br /&gt;&lt;br /&gt;Також частина блогів буде на англійській мові. Для чого це потрібно? Мабуть, для того, щоб потренуватися писати статті на англійській мові. Знадобиться ))&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-53618351909278798?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/53618351909278798/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=53618351909278798' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/53618351909278798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/53618351909278798'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/06/blog-post.html' title='Зміни в блозі'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-2203921899458367611</id><published>2008-06-20T19:49:00.018+03:00</published><updated>2008-06-23T03:49:23.814+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='BlazeDS'/><title type='text'>BlazeDS: фільтрування повідомлень, що передаються клієнтові</title><content type='html'>Останні два тижні знашовся час трохи побавитися із Flex та BlazeDS. Основна задача - знайти способи передачі повідомлень від сервера до клієнта, так, щоб клієнт отримував тільки повідомлення, на які він підписався. &lt;br /&gt;Задача - розглянути можливі варіанти. Можливі варіанти були вибрані, а саме:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;Subtopics&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Selectors&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Adaptive polling&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Dynamic destinations&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Може є більше, але це ті, до яких я добрався і з якими я погрався.&lt;br /&gt;&lt;br /&gt;Взагалі то, subtopics та selectors можна би було об'єднати, от тільки між ними є невеличка різниця. Використовуючи selectors, можна задати більш гнучку умову вибору повідомлень, які повинень отримувати consumer. Але зрешту, є така річ як &lt;code&gt;MultiTopicsConsumer&lt;/code&gt;. Перевірка на те, чи слід віправляти повідомленння клієнту в залежності від підписки на сабтопік чи вибірку по хедерах, виконується на стороні сервера. Іншими словами, до клієнта приходять тільки окремі повідомлення із тих, що вислані на підписаний ним destination. Клієнт отримує повідомлення, що задовільняють необхідну умову.&lt;br /&gt;&lt;br /&gt;Adaptive polling дозволяє розширювати функціональність BlazeDS, що відповідає за відправлення повідомлення клієнтові.  Тут також слід правильно вибрати, який саме із двох презавантажених методів використовувати у вашому випадку.&lt;br /&gt;Цей метод, дозволяє виконувати необхідну вам дію на повідомленнями, що передаються клієнтові. Тут ми і можемо виконувати гнучку і складну вибірку повідомлень, що ми будемо відправляти клієнтові.&lt;br /&gt;&lt;br /&gt;За останнім способом (dynamic destinations) я виконував динамічне створення окремого destination на ту чи іншу розсилку в процесі роботи сервера. А клієнти вже підписувалися на динамічну розсилку. Явні мінуси: це ресурси на створення нової підписки (які не є вже аж такими великими, щоб вважати це проблемою), а також необхідність відстежувати життя підписки та знищувати її якщо вона вже непотрібна.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-2203921899458367611?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/2203921899458367611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=2203921899458367611' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2203921899458367611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/2203921899458367611'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/06/blazeds.html' title='BlazeDS: фільтрування повідомлень, що передаються клієнтові'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-3944941879322194477</id><published>2008-06-08T02:28:00.004+03:00</published><updated>2008-06-08T02:45:22.352+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='News'/><title type='text'>Новини: 07 червня</title><content type='html'>&lt;ul&gt;&lt;br /&gt;&lt;li&gt;В реліз вийшла нова версія Spring Security під номером 2.0.2. &lt;a href="http://springframework.org/node/681"&gt;Детальніше...&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-3944941879322194477?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/3944941879322194477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=3944941879322194477' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3944941879322194477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3944941879322194477'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/06/07.html' title='Новини: 07 червня'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-4311150723465926163</id><published>2008-06-02T22:31:00.026+03:00</published><updated>2008-06-08T02:14:38.872+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='PermGen'/><title type='text'>OutOfMemoryError: PermGen</title><content type='html'>&lt;p&gt;Десь кілька місяців тому виявилося, що в проекті, над яким я працюю, знайшлася потворна бага. Відловити її було неможливо. В будь-який момент працювати з програмою ставало неможливо. В логах вивалювалася помилка &lt;code&gt;OutOfMemoryError: PermGen&lt;/code&gt;. &lt;br&gt;&lt;br /&gt;Звичайно, я з цим не вперший раз стикаюся, і вирішив спробувати старий добрий спосіб - прописати параметр до Джава машини &lt;code&gt;-XX:MaxPermSize&lt;/code&gt;. Отже, прописавши параметр &lt;code&gt;-XX:MaxPerSize=256m&lt;/code&gt;, я запустив &lt;code&gt;JBoss&lt;/code&gt;. І що? А нічого. Все одно програма вивалювалася... Так само непердбачувано і неочікувано :(.&lt;br&gt;&lt;br /&gt;Тоді я вирішив спробувати ще раз, але цього разу збільшив память для PermGen space вдвічі: &lt;code&gt;-XX:MaxPerSize=512m&lt;/code&gt;. Особливо це мені не допомогло, добитися впевнених 24/7 так і невийшло. І було вирішено, що слід ритися вглубь, не виправляти проблему, а викорінити причину!&lt;br /&gt;Порившись в інтернеті я надибав блог &lt;a href="http://blogs.sun.com/fkieviet/entry/how_to_fix_the_dreaded"&gt;by Frank Kieviet&lt;/a&gt;, в якому розповідалося про використання утиліт для Java 6: &lt;code&gt;jmap&lt;/code&gt; та &lt;code&gt;jhat&lt;/code&gt;. &lt;br&gt;&lt;br /&gt;&lt;code&gt;&lt;a href="http://java.sun.com/javase/6/docs/technotes/tools/share/jmap.html"&gt;jmap&lt;/a&gt;&lt;/code&gt; - дозволяє створювати дампи пам'яті Java програми.&lt;br /&gt;&lt;code&gt;&lt;a href="http://java.sun.com/javase/6/docs/technotes/tools/share/jhat.html"&gt;jhat&lt;/a&gt;&lt;/code&gt; - дозволяє представити інформацію дампа у зручному для користувача вигляді.&lt;br/&gt;&lt;br /&gt;Отож, використовуючи jmap я зробив дамп heap пам'яті запущеної програми в процесі її роботи. Я виконав команду&lt;br/&gt;&lt;br /&gt;&lt;b&gt;&lt;code&gt;&amp;gt;jmap -dump:format=b,file=dump1 3412&lt;/code&gt;&lt;/b&gt;&lt;br/&gt;&lt;br /&gt;цим самим вказавши, що слід виконати дамп пам'яті програми, зберегти її в бінарному форматі у файлі dump1. &lt;code&gt;3412&lt;/code&gt; - це pid Java програми, дамп пам'яті якої я робив. Для того, щоб отримати ідентифікатор процесу, у Windows введіть команду &lt;code&gt;tasklist&lt;/code&gt; і знайдіть відповідний &lt;code&gt;java.exe&lt;/code&gt; процес.&lt;br/&gt;&lt;br /&gt;Після того, як в мене вже був збережений у файлі дамп, я скористався програмою &lt;code&gt;jhat&lt;/code&gt;. Команда:&lt;br/&gt;&lt;br /&gt;&lt;b&gt;&lt;code&gt;&amp;gt;jhat dump1&lt;/code&gt;&lt;/b&gt;&lt;br/&gt;&lt;br /&gt;проаналізувала дамп і запустила веб-сервер, який по-замовчуванню слухає запити на порті 7000. Якщо потрібно буде одночасно запустити декілька jhat, то знайте - адрес порта можна змінити відповідним параметром. Слід також звернути увагу на параметр &lt;code&gt;-J&lt;/code&gt;. Всі параметри, які задаються після &lt;code&gt;-J&lt;/code&gt; потрапляються напряму до Java машини. В моєму випадку це знадобилося для того, щоб збільшити максимальну межу пам'яті, яку можна виділити. У випадку програми, яка працювала під JBoss AS 4.0.4, я змушений був запускати &lt;code&gt;jhat&lt;/code&gt; компандою&lt;br/&gt; &lt;b&gt;&lt;code&gt;&amp;gt;jhat -J-Xmx1536m dump&lt;/code&gt;&lt;/b&gt;&lt;br/&gt;&lt;br /&gt;Після старту &lt;code&gt;jhat&lt;/code&gt;, можна спокійно відкривати ваш олюблений броузер, і вводити адрес &lt;a href="http://localhost:7000/"&gt;http://localhost:7000/&lt;/a&gt;. Тепер можна переглядати дамп пам'яті програми, використовуючи набір функціоналу, який надається програмою.&lt;br/&gt;&lt;br /&gt;Скориставшися цією програмою, я визначив причину моєї проблеми &amp;ndash; не всі динамічно генеровані класи вигружалися; декотрі з них так і залишалися назавжди в пам'яті. Оскільки, PermGen Space (Permananent Generated Space) - це простір в пам'яті, в якому знаходяться довгоживучі (або вічноживучі в межах запущеної java-машини) об'єкти, а серед таких є класи та 'interned strings', то зрозуміло, що суть моєї проблеми в тому, що декотрі динамічно генеровані класи продовжували генеруватися, завантажуватися в пам'ять, але навідмінно від інших, вони залишалися там навічно. Рано чи пізно вільна пам'ять завершувалася, і програма уходила в аут із знойним повідомленням "OutOfMemoryError: PermGen".&lt;br/&gt;&lt;br /&gt;Але лікування цієї проблеми це вже зовсім інша історія... І наразі вона ще не закінчилася :(.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-4311150723465926163?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/4311150723465926163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=4311150723465926163' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4311150723465926163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/4311150723465926163'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/06/outofmemoryerror-permgen.html' title='OutOfMemoryError: PermGen'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-270191050393321990</id><published>2008-05-17T01:11:00.008+03:00</published><updated>2008-05-18T10:54:56.371+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='News'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Реліз Spring WebFlow 2.0</title><content type='html'>15 травня, &lt;a href="http://www.springframework.org"&gt;Spring Framework&lt;/a&gt; анонсувала вихід в реліз &lt;a href="http://www.springframework.org/go-webflow2"&gt;WebFlow версії 2.0&lt;/a&gt;. Серед проголошених основних фіч - це "першокласна" підтримка &lt;a href="http://en.wikipedia.org/wiki/JavaServer_Faces"&gt;Java Server Faces&lt;/a&gt; (Spring Faces), &lt;a href="http://en.wikipedia.org/wiki/AJAX"&gt;AJAX&lt;/a&gt; (Spring JavaScript).&lt;/br&gt;&lt;br /&gt;Spring WebFlow використовується як доповнення до вже існуючих веб-фреймворків (наприклад, Spring MVC, JSF). &lt;br/&gt;Даний фреймворк дозволяє представити веб аплікацію у вигляді flow'ів, кожен з яких містить набір станів та переходів між станами. Кожний такий flow можна уявити собі вигляді діаграми станів UML. Практично, діаграма станів використовується для того, щоб графічно змоделювати або показати набір станів в межах flow. Це є прекрасний спосіб вирішення навігації та роботи із станами в межах веб аплікації.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-270191050393321990?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/270191050393321990/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=270191050393321990' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/270191050393321990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/270191050393321990'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/05/spring-webflow-20.html' title='Реліз Spring WebFlow 2.0'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-8626472063204205963</id><published>2008-05-15T22:53:00.037+03:00</published><updated>2008-05-16T00:07:35.230+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'>"Implementation Patterns" by Kent Beck</title><content type='html'>&lt;img src="http://ecx.images-amazon.com/images/I/51JHn-6oNwL._SL175_.jpg"  border="0"/&gt;&lt;br /&gt;    В дорозі до Львову і назад я все-таки знайшов час, щоб дочитати до кінця книгу &lt;a href="http://en.wikipedia.org/wiki/Kent_Beck"&gt;Кента Бека (Kent Beck)&lt;/a&gt; &lt;i&gt;"Implementation Patterns"&lt;/i&gt;. Дана книжка є таким собі збірником паттернів по написанню коду. В дечому вона перехрещується із всім відомою книгою &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Code_Complete"&gt;"Code Complete"&lt;/a&gt;&lt;/i&gt;. Книга орієнтована на Java програмістів; приклади в книзі приводяться на Java, розглядається навіть Collection API, виникає навіть деколи відчуття, що декотрі шаблони підточені під Java. &lt;br/&gt;&lt;br /&gt;Взагалі, книжка має досить просту і зручну структуру. Ця стуктура позволяє вам перечитати книжку від корочки до корочки, а також користуватися як каталогом шаблонів. &lt;br/&gt;&lt;br /&gt;В ній можна знайти такі розділи:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;&lt;b&gt;Theory of Programming&lt;/b&gt; розказує про основні цінності та принципи створюваних програм. Виділяється 3 цінності ПЗ, що слід досягати &amp;ndash; це взаємодія, простота та розширюваність. &lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;b&gt;Class&lt;/b&gt; - біля 17 шаблонів (типів) класів, що зустрічатимуться програмісту при розробці програм. Цей розділ описує, які класи можуть бути, як слід виділяти та створювати класи та інтерфейси.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;b&gt;State.&lt;/b&gt; Такі шаблони, як &lt;code&gt;Direct Access, Indirect Access, Variable, Field, Var Args, Parameter&lt;/code&gt; та ще коло 20 патернів. Ці шаблони описують стан (дані) класу, як правильно організовувати стан, як правильно оформлювати доступ, ініціалізацію тощо.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;b&gt;Behavior.&lt;/b&gt; Ще 14 шаблонів повязаних із поведінкою. У доповненні до опису шаблонів пов'язаних із станом класів, подаються також шаблони поведінки, роботи із даними. Розглядаються потоки виконання програм і шаблони повідомлень, якими обмінюються класи.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;b&gt;Methods.&lt;/b&gt; Ну і як без методів. Цій частині виділяється окремий розділ, який описує такі шаблони, як &lt;code&gt;Factory Method, Helper Method, Query Method, Method Object, Creation, Composed Method etc.&lt;/code&gt; Я в свою чергу звернув увагу, на &lt;code&gt;Method Object&lt;/code&gt;: перечитуючи його, я згадував усі ті рази коли він міг мені знадобитися.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;b&gt;Collections.&lt;/b&gt; Автор звертає нашу увагу на бібліотеку колекцій, що існує в Java SE. Доречі, мене зацікавили графіки-порівняння залежності часу виконання операцій від кількості елементів для різних реалізацій контейнерів.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;b&gt;Evolving Frameworks.&lt;/b&gt; Окремий розділ, присвячений фреймоворкам.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Книжка має всього 176 сторінок та опис понад 100 різних шаблонів. В цілому, книга дуже цікава! Підхід автора до постановки проблеми та висвітлення рішення мені особисто сподобався. Не буду казати, що ця книга must read, але якщо прочитаєте, то і самі все зрозумієте ;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-8626472063204205963?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/8626472063204205963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=8626472063204205963' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8626472063204205963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/8626472063204205963'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/05/implementation-patterns-by-kent-beck.html' title='&quot;Implementation Patterns&quot; by Kent Beck'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-3314149103786491615</id><published>2008-04-26T22:21:00.036+03:00</published><updated>2008-05-16T00:09:33.619+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Spring 2.5: використання аннотацій</title><content type='html'>Про те, що вийшов Spring Framework (&lt;a href="http://www.springframework.org/"&gt;www.springframework.org&lt;/a&gt;) версії 2.5, я знав вже давно (відносно давно звичайно). Читав про нові можливості даної версії, пробував навіть щось трохи. Але то все було просто так, для себе. Недавно появилася можливість побавитися із Spring 2.5 більш глибше. І я з радістю нею скористався.&lt;br /&gt;Основним моментом, який був для мене цікавим - це використання анотацій у доповнення до XML конфігурації. Саме про це я вирішив трохи написати.&lt;br /&gt;&lt;br /&gt;Головним питанням було -- навіщо анотації?&lt;br /&gt;Іншими цікавими питаннями були:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;які анотації можна використовувати?&lt;/li&gt;&lt;li&gt;як їх використовувати?&lt;/li&gt;&lt;li&gt;чи можливо працювати і дальше без них?&lt;/li&gt;&lt;li&gt;як можна включати і виключати використання анотацій?&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;і багато ще інших питань, які виникали по ходу справи.&lt;br /&gt;&lt;br /&gt;Отож, про все по порядку.&lt;br /&gt;Анотації не підтримуються по замовчуванню. Для того, щоб їх використовувати, потрібно вказати Spring, що ви хочете працювати і з ними тоже. Для цьому слід добавити у ваш spring.xml наступний рядок:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;context:annotation-config/&amp;gt;.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Namespace context підключається так&lt;br /&gt;&lt;pre name="code"&gt;&lt;br /&gt;xmlns:context="http://www.springframework.org/schema/context"&lt;br /&gt;xsi:schemaLocation=" http://www.springframework.org/schema/context&lt;br /&gt;               http://www.springframework.org/schema/context/spring-context-2.5.xsd"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Після цього, в нас появляється можливість використовувати анотації.&lt;br /&gt;А тепер детальніше про самі анотанції. Так ми вже можемо використовувати їх, але які вони є, навіщо вони використовуються?&lt;br /&gt;Найбільш поширеною видається анотації &lt;code&gt;@Autowired&lt;/code&gt;. Дана анотація, вказує що в контейнер Spring повинен виконати автоматичне встановлення значення. Дану анотацію можна використовувати для автоматичного встановлення значення в конструкторі, для поля класу, для сеттера. Наприклад:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class DocumentManager {&lt;br /&gt;   @Autowired&lt;br /&gt;   private DocumentFinder documentFinder;&lt;br /&gt;   private DocumentDao documentDao;&lt;br /&gt;   private Document documentPrototype;&lt;br /&gt;&lt;br /&gt;   @Autowired&lt;br /&gt;   public DocumentManager(DocumentDao documentDao) {&lt;br /&gt;       this.documentDao = documentDao;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Autowired&lt;br /&gt;   public void setPrototype(Document document) {&lt;br /&gt;       documentPrototype = prototype;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;В даному випадку автозаповнення за допомогою анотації &lt;code&gt;@Autowired&lt;/code&gt;, Spring буде виконувати на основі типів полів чи аргументів. Але виникає проблема, коли, наприклад, у вас може бути більше одного біна із типом &lt;code&gt;DocumentFinder&lt;/code&gt; або &lt;code&gt;Document&lt;/code&gt;. Що робити тоді, як Spring має знати яке саме значення слід вставити в певне поле? І саме тут вступає у гру анотація &lt;code&gt;@Qualifier&lt;/code&gt;.&lt;br /&gt;Анотація &lt;code&gt;@Qualifier&lt;/code&gt; дозволяє вказати, який саме &lt;code&gt;container-managed bean&lt;/code&gt; використовувати як значення для заповнення. Дану анотацію можна використовувати як для полів класу, так і для параметрів конструктора або інших методів, так само і для сеттерів. Назва біна, який повинен бути вставленим як значення поля чи параметра вказується як value анотації &lt;code&gt;@Qualifier&lt;/code&gt;. Доволі просто і зручно, самі подивіться на код:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class DocumentManager {&lt;br /&gt;&lt;br /&gt;   @Autowired&lt;br /&gt;   @Qualifier("defaultDocumentFinder")&lt;br /&gt;   private DocumentFinder documentFinder;&lt;br /&gt;&lt;br /&gt;   private DocumentDao documentDao;&lt;br /&gt;&lt;br /&gt;   private Document documentPrototype;&lt;br /&gt;&lt;br /&gt;   @Autowired&lt;br /&gt;   public DocumentManager(@Qualifier("hibernateDocumentDao")DocumentDao documentDao) {&lt;br /&gt;      this.documentDao = documentDao;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Autowired&lt;br /&gt;   public void setPrototype(@Qualifier("prototypeDocument")Document document) {&lt;br /&gt;      documentPrototype = prototype;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Доречі, Spring дозволяє за допомогою XML вказати явно, який &lt;code&gt;qualifier&lt;/code&gt; у певного bean. Для цього використовується піделемент &lt;code&gt;&amp;lt;qualifier&amp;gt;&lt;/code&gt; елемента &lt;code&gt;&amp;lt;bean&amp;gt;&lt;/code&gt;. Він має такі атрибути, як:&lt;br /&gt;- type  - тип анотації, що використовується (про це пізніше)&lt;br /&gt;- value - це значення унікальне для даного біна.&lt;br /&gt;&lt;br /&gt;Наприклад, якщо в коді вказано:&lt;br /&gt;&lt;pre name="code" class="java"&gt;  &lt;br /&gt;@Autowired&lt;br /&gt;@Qualifier("prototypeDocument")&lt;br /&gt;public void setPrototype(Document document) {&lt;br /&gt;   documentPrototype = prototype;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;, то в XML&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;bean class="Document"&amp;gt;&lt;br /&gt;  &amp;lt;qualifier value="prototypeDocument"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean class="Document"&amp;gt;&lt;br /&gt;  &amp;lt;qualifier value="privateDocument"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;І як ви вже певно зрозуміли, при автозаповнення буде використаний перший bean, тому що його &lt;code&gt;qualifier value&lt;/code&gt; є &lt;code&gt;prototypeDocument&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Але це ще не всі можливості, які надає Spring у питанні вирішення, який саме bean повинен бути використаний для автозаповнення. Так, наприклад, ви можете створювати власні анотації, які використовувати замість &lt;code&gt;@Qualifier&lt;/code&gt;.&lt;br /&gt;Наприклад:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;@Target({ElementType.FIELD, ElementType.PARAMETER})&lt;br /&gt;@Retention(RetentionPolicy.RUNTIME)&lt;br /&gt;@Qualifier&lt;br /&gt;public @interface DocumentFinder {&lt;br /&gt;  String documentType();&lt;br /&gt;  String finderScope();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;тоді&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;@Autowired&lt;br /&gt;@DocumentFinder(documentType="MSWord", finderScope="local")&lt;br /&gt;private DocumentFinder documentFinder;&lt;br /&gt;&lt;/pre&gt;а в XML&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;bean class="DocumentFinder"&amp;gt;&lt;br /&gt;   &amp;lt;qualifier type="annotation.DocumentFinder"&amp;gt;&lt;br /&gt;      &amp;lt;attribute name="documentType" value="MSWord"/&amp;gt;&lt;br /&gt;      &amp;lt;attribute name="finderScope" value="local"/&amp;gt;&lt;br /&gt;   &amp;lt;/qualifier&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;І це ще навіть не всі можливості...&lt;br /&gt;Так, наприклад, я не розказав про &lt;code&gt;@Resource&lt;/code&gt;. А також і не згадав досі про можливість використання компонентів, які оголошенні за допомогою анотацій.&lt;br /&gt;&lt;br /&gt;Але про це все або читайте в туторіалі від Spring або вже у наступній статті.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-3314149103786491615?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/3314149103786491615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=3314149103786491615' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3314149103786491615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/3314149103786491615'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2008/04/spring-25.html' title='Spring 2.5: використання аннотацій'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-1828178357487138719</id><published>2007-12-16T19:04:00.001+02:00</published><updated>2008-05-16T00:09:16.923+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Кешування (Caching)'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Кешування другого рівня в Hibernate.</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Частина II: Бібліотеки кешування для Hibernate&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;  &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Кеш другого рівня в&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; може бути підключеним і може бути в межах процесу або кластера. Можуть бути різні реалізації кешу другого рівня, існують кілька вже готових реалізацій на основі готових движків кешування. Але можна реалізувати власний движок і підключити його за допомогою реалізації інтерфейсу &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;org&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;CacheProvider&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Визначають наступні провайдери кешу другого рівня&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-align: justify; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Підтримка кешування другого рівня в межах одного процесу однієї віртуальної машини. Може виконувати зберігання кешу як в оперативній памяті, так і на диск.&lt;span style=""&gt;  &lt;/span&gt;Підтримує кешування запитів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-align: justify; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;OSCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; (&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;OpenSymphony&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;). Підтримка кешування другого рівня в межах одного процесу однієї віртуальної машини. Підтримує кешування запитів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-align: justify; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;SwarmCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Підтримка кешування другого рівня в межах кластера. Не підтримує кешування запитів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-align: justify; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;JBossCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Підтримка кешування другого рівня в межах кластера. Підтримує кешування запитів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Про підтримку стратегій кешування різними провайдерами можна дізнатися із наступної таблиці:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0"&gt;  &lt;tbody&gt;&lt;tr style=""&gt;   &lt;td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Провайдер&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Read-only&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Read-write&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Nonstrict-read-write&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.75pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Transactional&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;  &lt;/tr&gt;  &lt;tr style=""&gt;   &lt;td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.75pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;  &lt;/tr&gt;  &lt;tr style=""&gt;   &lt;td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;OSCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.75pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;  &lt;/tr&gt;  &lt;tr style=""&gt;   &lt;td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;SwarmCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.75pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;  &lt;/tr&gt;  &lt;tr style=""&gt;   &lt;td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;JBossCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.7pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 95.75pt;" valign="top" width="128"&gt;   &lt;p class="MsoNormal" style="text-align: center;" align="center"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;+&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Підтримка кешування другого рівня в &lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Кешування другого рівня в &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; потрібно увімкнути, для того, щоб його використовувати. Увімкнути кешування другого рівня можна встановши &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;property&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; в конфігурації сесії &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="UK"&gt;&amp;lt;property name="cache.use_second_level_cache"&amp;gt;true&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Якщо необхідно увімкнути&lt;span style=""&gt;  &lt;/span&gt;також кешування для запитів, то слід також встановити значення для &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;property&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; в конфігурації сесії &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="UK"&gt;&amp;lt;property name="hibernate.cache.use_query_cache"&amp;gt;true&amp;lt;/property&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Також необхідно вказати клас провайдера кешування, а для цього треба задати наступний &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;property&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; в конфігурації сесії &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; : &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt; &lt;/span&gt;- &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;для провайдера&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="UK"&gt;&amp;lt;property name="cache.provider_class"&amp;gt;org.hibernate.cache.EhCacheProvider&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="EN-US"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;для провайдера &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;OSCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&amp;lt;property name="cache.provider_class"&amp;gt;org.hibernate.cache.OSCacheProvider&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="EN-US"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;для провайдера &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;SwarmCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&amp;lt;property name="cache.provider_class"&amp;gt;org.hibernate.cache.SwarmCacheProvider&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Але для того, щоб кешування другого рівня було в дії, слід позначити хоча б один клас для кешування. Позначити певний клас для кешування можна двома способами:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;ol style="margin-top: 0cm;" start="1" type="1"&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;В описі маппінгу класу у файлі *.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;hbm&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;xml&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; добавити елемент &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; із відповідним значенням.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;  &lt;p class="MsoNormal" style="margin-left: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&amp;lt;class name=”org.prisoft.sample.hibernate.Country” table=”Country”&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="UK"&gt; mutable="false"&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;      &lt;/span&gt;&amp;lt;cache usage="read-only"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;      &lt;/span&gt;…&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&amp;lt;/class&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 35.4pt; text-align: justify;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Вище описаний клас &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Country&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, який мапиться на таблицю &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Country&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Ця таблиця є словником країн. Словник зміні не підлягає, тобто значення не добавляється, не редагується та не видаляється.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; вказує на те, що дані підлягають кешуванню, стратегія кешування &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;read&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;-&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;only&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;span style=""&gt;  &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;ol style="margin-top: 0cm;" start="2" type="1"&gt;&lt;li class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;У файлі конфігурації сесії &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cfg&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;xml&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Для цього використовується      елемент &amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;class&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;-&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;gt;, який наводиться після списку ресурсів. Ось      як може описуватися кешування для класу &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Country&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="UK"&gt;&amp;lt;hibernate-configuration&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="UK"&gt;&lt;span style=""&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="UK"&gt;&amp;lt;session-factory&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;            &lt;/span&gt;….&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;            &lt;/span&gt;&amp;lt;mapping resource=”org/prisoft/sample/hibernate/Country.hbm.xml”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;            &lt;/span&gt;….&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;            &lt;/span&gt;&amp;lt;class-cache class=”org.prisoft.sample.hibernate.Country” &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;                                             &lt;/span&gt;usage=”read-only”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;      &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 36pt; text-indent: 34.8pt;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&amp;lt;/session-factory&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="EN-US"&gt;&lt;span style=""&gt;      &lt;/span&gt;&amp;lt;/hibernate-configuration&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 9pt; text-align: justify;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Я надаю перевагу конфігурації кешування другого рівня через файл &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;hibernate.cfg.xml&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, оскільки так видно повний список класів, що підлягають кешуванню, а також при необхідності, можна легко відключити кешування. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, ми розглянули, як включити кешування другого рівня, а також як вказати які саме ентіті підлягають кешуванню. Ми не розглянули, як задається кешування для запитів. &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Також ми не розглянули таке поняття, як регіони. &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Регіони – це так би мовити іменовані екземпляри кешу, в якому знаходяться різні класи із різними політиками часу на існування. По замовчуванню, ім’я регіону складає повна назва класу (якщо це кеш класу) або повна назва класу плюс імя &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;property&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; класу (якщо це колекція). За допомогою &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;property&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; сесії &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-GB"&gt;hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-GB"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-GB"&gt;region&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;_&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-GB"&gt;prefix&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Тоді ім’я регіону буде складатися із префіксу та повного імені класу. Вказати ім’я регіону можна явно за допомогою атрибута &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;region&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; в елементі &amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;gt; або &amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;class&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;-&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache (&lt;a href="http://ehcache.sourceforge.net/"&gt;http://ehcache.sourceforge.net&lt;/a&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Останнє обновлення аплікації це є &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;ehcache-1.4-beta, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;яка вийшла 1 січня 2008. А це означає, що продукт не тільки живий, але і розвивається. Розповсюджується &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EhCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; за ліцензією &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;The&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Apache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Software&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;License&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Version&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; 2.0. Спонсори там також далеко не з послідніх. Так що, проект живе і розвивається. Не може не радувати повна підтримка &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;JSR&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;107 (&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;JCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;API&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;). &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Серед вказаних характеристик слід відзначити:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Простота (&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;API&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; є досить простим, початкова конфігурація також не є необхідною).&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Залежність тільки від &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;commons&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;-&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;logging&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; та &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;commons-collections&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Вони в свою чергу також поширюються за &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;APL&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Та й більшість проектів їх використовує. То ж, ця залежність не є проблематичною.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Кешування в оперативній пам’яті та на диск. Підтримка великих розмірів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Підтримка великої кількості кешів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Підтримка розширень для кешу (а також розширення для загружчиків та обробників виключень).&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;А також багато чого іншого, про що ви можете точніше дізнатися за адресом &lt;a href="http://ehcache.sourceforge.net/features.html"&gt;http://ehcache.sourceforge.net/features.html&lt;/a&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Як уже зазначено, можна і не конфігурувати &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; Але я не думаю, що це хороша ідея. Нам вона явно не підходить. Ми повинні навчитися конфігурувати &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EhCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, конфігурація &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; знаходиться у файлі &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;ehcache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;xml&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, який у свою чергу знаходиться в класспасі аплікації.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, структура конфігураційного файла:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;lt;ehcache&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;&amp;lt;diskStore …/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;&amp;lt;defaultCache …/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;&amp;lt;cache name=”...” …/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&amp;lt;/ehcache&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt; &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Конфігураційний файл може містити не тільки ці елементи, але й інші. Але вони розглядатися не будуть.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Роглянемо детальніше ці елементи.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;diskStore&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;path&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;=”&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;java&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;io&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;tmpdir&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;”/&amp;gt; - вказує шлях до каталогу, де файли кешу створюються. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Наступні значення є можливими:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;user&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;home&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt; – &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;домашній каталог користувача;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;user&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;dir&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt; – &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;текучий робочий каталог користувача;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt;" lang="UK"&gt;&lt;span style=""&gt;-&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;          &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;java&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;io&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;tmpdir&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; – каталог тимчасових файлів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Можна також вказувати субдиректорії, наприклад&lt;span style=""&gt;  &lt;/span&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;diskStore&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;path&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;=”&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;java&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;io&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;tmpdir&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;/&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;/&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;myapp&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Конфігурація кешу, який не описаний за допомогою власного &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; елемента, відбувається через &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;defaultCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&amp;lt;defaultCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;maxElementsInMemory=”&lt;st1:metricconverter productid="10000”" st="on"&gt;10000”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;eternal=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;timeToIdleSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;timeToLiveSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;overflowToDisk=”true”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;diskSpoolBufferSizeMB=”&lt;st1:metricconverter productid="30”" st="on"&gt;30”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;maxElementsOnDisk=”&lt;st1:metricconverter productid="1000000”" st="on"&gt;1000000”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;diskPersistent=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;diskExpiryThreadInternalSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;memoryStoreEvictionPolicy=”LRU”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Можна також задавати конфігурацію для окремого кешу; а для цього використовується наступний елемент&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;с&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;ache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;name=”CacheName”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;maxElementsInMemory=”&lt;st1:metricconverter productid="10000”" st="on"&gt;10000”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;eternal=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;timeToIdleSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;timeToLiveSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;overflowToDisk=”true”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;maxElementsOnDisk=”&lt;st1:metricconverter productid="1000000”" st="on"&gt;1000000”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;diskPersistent=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;diskExpiryThreadInternalSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;         &lt;/span&gt;memoryStoreEvictionPolicy=”LRU”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;А тепер детальніше про кожен атрибут.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;mame&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt; – &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;назва кешу; назва, як ви вже, мабуть, зрозуміли має бути унікальна.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;maxElementsInMemory&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; – максимальна кількість об’єктів, які будуть створені та зберігатися в кеші в оперативній пам’яті.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;maxElementsOnDisk&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; – максимальна кількість об’єктів, які будуть збережені на диск.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;eternal&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt; – &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;вказує на те, чи є елементи вічними. Якщо вони є вічними, то будь-які настройки &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Idle&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; та &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Live&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Seconds&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; ігноруються, елементи зберігаються до кінця.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;timeToIdleSeconds&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; – &lt;span style=""&gt; &lt;/span&gt;час життя невикористаного елемента кешу (за умови, якщо &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;eternal&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;рівний &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;false&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;). Якщо значення 0, то це значить, що елемент може залишатися в кеші в стані не використовуваного нескінченний період.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;timeToLiveSeconds&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;– час життя елемента кешу (за умови, якщо &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;eternal&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;рівний &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;false&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;). Якщо значення 0, то це значить, що елемент може залишатися в кеші в стані невикористаного нескінченний період.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;overflowToDisk&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; – вказує на те, чи зберігати елементи на диск, якщо досягнуто максимуму елементів в пам’яті. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;diskPersistent&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; -&lt;span style=""&gt;  &lt;/span&gt;чи зберігаються закешовані дані між пере запуском віртуальної машини. Значення по-замовчуванню &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;false&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;diskExpiryThreadInternalSeconds&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; – кількість секунд, через які відбувається запуск потоку очищення диску від елементів кешу, що завершили свій час життя.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;memoryStoreEvectionPolicy&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. Розрізняються наступні політики &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;LRU&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; – &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Least&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Recently Used, FIFO – First In First Out, LFU &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;– &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Last Frequently Used.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-right: 3.8pt;"&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Приклад аплікації із використанням кешу &lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, розглянуто трохи теорії, а тепер ближче до практики. Для цього було створено просту аплікацію, яка містить 4 доменних об’єкта: &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Country&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Materials&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Product&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;ProductMaterial&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, ми маємо аплікацію, яка містить інформацію про матеріали (назва, код, ціна, країна виробник), про продукцію (назва, код, ціна, країна виробник, матеріали із яких виготовлена продукція) і власне словник країн виробників.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Кешування класів та стратегії кешування описані у файлі &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cfg&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;xml&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;cfg&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;xml&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; має вигляд:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;lt;hibernate-configuration&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;    &lt;/span&gt;&amp;lt;session-factory&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;property name="hibernate.connection.url"&amp;gt;jdbc:mysql://localhost/proregister&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;property name="hibernate.connection.driver_class"&amp;gt;com.mysql.jdbc.Driver&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;property name="hibernate.connection.username"&amp;gt;root&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;property name="hibernate.connection.password"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;property name="hibernate.show_sql"&amp;gt;false&amp;lt;/property&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;mapping resource="org/prisoft/sample/proregister/objects/Country.hbm.xml"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;    &lt;/span&gt;&lt;span style=""&gt;    &lt;/span&gt;&amp;lt;mapping resource="org/prisoft/sample/proregister/objects/Material.hbm.xml"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;mapping resource="org/prisoft/sample/proregister/objects/Product.hbm.xml"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;mapping resource="org/prisoft/sample/proregister/objects/ProductMaterial.hbm.xml"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;class-cache class="org.prisoft.sample.proregister.objects.Country" usage="read-only"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;class-cache class="org.prisoft.sample.proregister.objects.Material" usage="read-write"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;class-cache class="org.prisoft.sample.proregister.objects.Product" usage="read-write"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;        &lt;/span&gt;&amp;lt;class-cache class="org.prisoft.sample.proregister.objects.ProductMaterial" usage="read-write"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;    &lt;/span&gt;&amp;lt;/session-factory&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;lt;/hibernate-configuration&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Клас &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Country&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; має стратегію кешування &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;read&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;-&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;only&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, в той час як всім іншим задана стратегія &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;read&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;-&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;write&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;. &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Country&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; є по факту незмінним словником країн; його не можна змінювати.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Кеши класів &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Material&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Product&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;та &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;ProductMaterial&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; повинні підтримувати зміну, оскільки елементи можуть як добавлятися, так і редагуватися та видалятися. Саме тому їм задана стратегія &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;read-write.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Аплікація працюватиме із базою даних на одній машині, тому виконувати кешування на диск немає потреби. Окрім того, кількість даних є невеликою, тому їх можна спокійно зберігати в базу даних. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Для детальної конфігурації &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; потрібно конфігурувати кожен кеш у файлі &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;ehcache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;xml&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, конфігурація має наступний вигляд:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;lt;ehcache&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;    &lt;/span&gt;&amp;lt;diskStore path="java.io.tmpdir"/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;    &lt;/span&gt;&amp;lt;defaultCache&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;            &lt;/span&gt;maxElementsInMemory="10000"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;            &lt;/span&gt;eternal="false"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;  &lt;/span&gt;&lt;span style=""&gt;          &lt;/span&gt;timeToIdleSeconds="120"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;            &lt;/span&gt;timeToLiveSeconds="120"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;            &lt;/span&gt;overflowToDisk="false"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;            &lt;/span&gt;diskPersistent="false"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;            &lt;/span&gt;diskExpiryThreadIntervalSeconds="120"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;            &lt;/span&gt;memoryStoreEvictionPolicy="LRU"/&amp;gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;[&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;тут має бути конфігурація кешів, розглянута дальше&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;]&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&amp;lt;/ehcache&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, ми вказали на каталог для файлів кешування та конфігурацію кешу по-замовчуванню. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Нижче подана конфігурація кешу для класу &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Country&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;"&gt;. &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Задаємо максимальну кількість елементів в пам’яті, забороняється записувати дані на диск, дані можуть зберігатися тривалий час. Якщо кількість елементів в пам’яті перевищує 200, то тоді відбувається очистка кешу.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&amp;lt;cache name="org.prisoft.sample.proregister.objects.Country "&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt; &lt;/span&gt;&lt;span style=""&gt;          &lt;/span&gt;maxElementsInMemory="200"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;           &lt;/span&gt;eternal="true"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;span style=""&gt;           &lt;/span&gt;overflowToDisk="false"/&amp;gt;&lt;span style=""&gt;       &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Настройка кешу для об’єктів &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Product&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Material&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt; &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;та &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;ProductMaterial&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; має відмінності, оскільки ці об’єкти можуть змінюватися, тому для них задана конфігурація тривалості існування елементів кешу. Конфігурація подана нижче.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&amp;lt;cache name=”org.prisoft.sample.proregister.Product” &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;maxElemenentsInMemory=”&lt;st1:metricconverter productid="2000”" st="on"&gt;2000”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;eternal=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;overflowToDisk=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;timeToIdleSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;timeToLiveSeconds=”300”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&amp;lt;cache name=”org.prisoft.sample.proregister.Material” &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;maxElemenentsInMemory=”&lt;st1:metricconverter productid="5000”" st="on"&gt;5000”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;eternal=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;overflowToDisk=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;timeToIdleSeconds=”&lt;st1:metricconverter productid="240”" st="on"&gt;240”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;timeToLiveSeconds=”300”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&amp;lt;cache name=”org.prisoft.sample.proregister.ProductMaterial” &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;maxElemenentsInMemory=”&lt;st1:metricconverter productid="10000”" st="on"&gt;10000”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;eternal=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;overflowToDisk=”false”&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;timeToIdleSeconds=”&lt;st1:metricconverter productid="120”" st="on"&gt;120”&lt;/st1:metricconverter&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="text-indent: 35.4pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt; &lt;/span&gt;timeToLiveSeconds=”120”/&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Як бачите, для різних кешів задана різна кількість елементів в памяті. Атрибут &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;eternal&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; має значення &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;false&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, тому конфігурація періоду існування елементів у кеші не буде ігноруватися. Дані не зберігаються на диск для жодного із кешів, використовуваних в аплікації.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Отже, ми розглянули які існують провайдери кешу другого рівня для &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;, також ми розглянули, як настроїти &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt; для використання кешу другого рівня для класів (проте не зачепили теми кешування запитів та колекцій). Розглянуто було також більш детально провайдер &lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EHCache&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;&lt;i style=""&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="UK"&gt;Додаткова література&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21.75pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;1.&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;Hibernate In Action, Manning Publications, 2005&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21.75pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;span style=""&gt;2.&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;EhCache User Guide at http://ehcache.sourceforge.net/EhcacheUserGuide.html&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21.75pt; text-indent: -18pt;"&gt;&lt;span style="font-size: 10pt; font-family: Verdana;" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-1828178357487138719?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/1828178357487138719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=1828178357487138719' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1828178357487138719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/1828178357487138719'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2007/12/hibernate.html' title='Кешування другого рівня в Hibernate.'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-131947665105489199.post-7022610622462307056</id><published>2007-11-24T12:50:00.001+02:00</published><updated>2008-05-16T00:08:57.731+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Кешування (Caching)'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>Кешування другого рівня в Hibernate.</title><content type='html'>&lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Частина I: Трохи теорії&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Є багато способів пришвидшити роботу Hibernate. Одним із них є кешування другого рівня (second level cache).&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Для мене він знадобився при оптимізації роботи проекту, який використовує Hibernate 3.2.3. В межах аплікації використовується кілька наборів даних, які рідко змінюються. Декотрі дані взагалі не змінюються. Витягувати їх із бази даних кожен раз виходить доволі накладно і навіть довго. Після використання кешування, на звичайній машині різниця почала відмічатися одразу ж.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Взагалі про розгляді кешування в Hibernate, слід розрізняти кешування першого та другого рівнів. Кешування першого рівня є обовязковим, його не можна відключити. Це є кешування рівня одиниці виконання роботи (unit of work) і виконується воно через Session.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Трохи детальніше про кешування першого рівня, адже воно є необхідним для розуміння кешування другого рівня. Перш за все, слід зрозуміти, що це є кешування перстистетних об'єктів, тобто, в межах однієї Session, кешуються об’єкти класу, а не окремі дані, і отримуються для одного і того самого же рядка в базі даних один і той самий об'єкт. Що ж це дає, і чому зрозблено саме так? По-перше, це дозволяє виконувати ідентифікацію по об’єкту, а не по значенню в межах однієї сесії. По-друге, це дозволяє зберігати інформацію про зміни до рядку в межах одного об’єкта, що уже спасає від будь-яких подальших проблем пов’язаних із синхронізацією із базою даних. Отже, кешування першого рівня, використовується в межах сесії одного користувача, і не впливає на роботу інших користувачів. Це пришвидшує роботу.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Кешування другого рівня має зовсім інші межі використання. Навідміну від кешування першого рівня (яке використовується в межах запиту користувача або бізнес транзакції користувача), кешування другого рівня використовується в межах процесу або кластера виконання аплікації. Цей кеш є спільним для багатьох користувачів системи, відповідно, його потрібно осторожно використовувати, та володіти основними правилами.&lt;span lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Перш за все, слід сказати, що кеш другого рівня в &lt;span lang="EN-US"&gt;Hibernate&lt;/span&gt; може мати межі процесу або кластера. Всі сесії використовують спільний кеш. Фактично кеш другого рівня має межі &lt;span lang="EN-US"&gt;SessionFactory&lt;/span&gt;, в той час як кеш першого рівня має межі &lt;span lang="EN-US"&gt;Session&lt;/span&gt;. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Для того, щоб робота кешу другого рівня була задовільною в багатокористувацькому середовищі, слід розуміти стратегії кешування. Стратегія кешування для об’єкта кешування встановлюється незалежно.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Так виділяють наступні стратегії кешування: &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt; font-family: verdana;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size:100%;"&gt;&lt;span style=""&gt;-&lt;span style=""&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span lang="EN-US"&gt;read&lt;/span&gt;&lt;span lang="RU"&gt;-&lt;/span&gt;&lt;span lang="EN-US"&gt;only&lt;/span&gt; – для об’єктів, що не змінюються ніколи в межах роботи аплікації.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; font-family: verdana;"&gt;&lt;span style="font-size:100%;"&gt;Типове для використання у випадку, якщо значення об’єктів не змінюється в процесі роботи аплікації (наприклад, ролі користувачів, список країн, мов, інші специфічні словники). Для подібних об’єктів можна також використовувати &lt;span lang="EN-US"&gt;mutable&lt;/span&gt; = “&lt;span lang="EN-US"&gt;false&lt;/span&gt;”, що дозволяє &lt;span lang="EN-US"&gt;Hibernate&lt;/span&gt; пришвидшувати роботу для незмінюваних об’єктів.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt; font-family: verdana;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size:100%;"&gt;&lt;span style=""&gt;-&lt;span style=""&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span lang="EN-US"&gt;read&lt;/span&gt;-&lt;span lang="EN-US"&gt;write&lt;/span&gt;&lt;span lang="EN-US"&gt; &lt;/span&gt;– для об’єктів, що можуть змінюватися в межах роботи аплікації, але частота зміни не є великою.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; font-family: verdana;"&gt;&lt;span style="font-size:100%;"&gt;Підходить для використання у більшості випадків. Велика кількість об’єктів в системі змінюється, але при цьому кешування об’єктів є необхідною для покращення роботи.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-left: 21pt; text-indent: -18pt; font-family: verdana;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-size:100%;"&gt;&lt;span style=""&gt;-&lt;span style=""&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span lang="EN-US"&gt;nonstrict&lt;/span&gt;&lt;span lang="EN-US"&gt; &lt;/span&gt;&lt;span lang="EN-US"&gt;read&lt;/span&gt;-&lt;span lang="EN-US"&gt;write&lt;/span&gt; – для об’єктів, що можуть змінюються в процесі роботи аплікації дуже рідко.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Кеш другого рівня дозволяє зберігати дані як в оперативній пам’яті так і на жорсткому диску. Зберігання даних на жорсткому диску актуально у випадках, коли аплікація та база даних знаходяться на різних машинах.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Коли відбувається загрузка об’єкта за допомогою &lt;span lang="EN-US"&gt;Session&lt;/span&gt;, перш за все, &lt;span lang="EN-US"&gt;Session&lt;/span&gt;&lt;span lang="EN-US"&gt; &lt;/span&gt;виконує перевірку кешу на рахунок наявності в ньому об’єкту із відповідною значенням поля ідентифікації. Перевірка виконується у випадку, якщо для даного типу включено кешування другого рівня. Отже, якщо кеш містить закешований об’єкт відповідним значенням поля ідентифікації, то відбувається створення ново об’єкта у віртувальній машині та заповнення його даними. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Звідси можна зробити наступний висновок. В кеші зберігаються не об’єкти віртуальної машини, а прості дані. На основі цих даних, відбувається заповнення новоствореного об’єкту.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: verdana;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Якщо ж кеш не містить шуканий об’єкт, то відбувається запит до бази даних, і якщо рядок із таким ідентифікатором все-таки є в базі даних, то відбувається його поміщення в кеш. Тепер кеш містить запис для рядка із даним ідентифікатором. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/131947665105489199-7022610622462307056?l=blog.khmelyuk.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.khmelyuk.com/feeds/7022610622462307056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=131947665105489199&amp;postID=7022610622462307056' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7022610622462307056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/131947665105489199/posts/default/7022610622462307056'/><link rel='alternate' type='text/html' href='http://blog.khmelyuk.com/2007/11/hibernate-i.html' title='Кешування другого рівня в Hibernate.'/><author><name>Ruslan Khmelyuk</name><uri>http://www.blogger.com/profile/08483230152299597189</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/-irWFgcZHcaI/TjJkA-ztZGI/AAAAAAAAAeU/fWeBtt-oblo/s220/Img-137-small.jpg'/></author><thr:total>0</thr:total></entry></feed>
