Общее·количество·просмотров·страницы

Java Dev Notes - разработка на Java (а также на JavaScript/Python/Flex и др), факты, события из АйТи

вторник, 29 сентября 2009 г.

Кеширование новостей - запись данных в файл, кодировки, локи на файл

Итак, есть задача - сделать кеширование новостей на сервере. Сейчас у нас новости тянутся с блогпота - читается фид блога (формат Atom), и затем они транслируются на сайте.

Кешируем следующим образом: сохраняем XML контент в файл на сервере. Стратегия обновления файла: если дата создания файл отличается от сегодняшней, то тащим новости с блогспота. Если же дата такая же, то не трогаем файл. Т.е. если у нас нет запросов к сайту, то файл с фидами не обновляется. Если запросы есть, то он обновляется раз в сутки.

Можно было конечно не заморачиваться с этим, и сделать попроще: используя cron раз в сутки запускать программку, которая пишет фиды с блогспота в файл. Соответственно, в java-программке не надо ничего писать, а просто лишь читать файл с сервера.

Итак, код чтения файла:

ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
 
String filename = "newsfeed.xml";
String realPath = getServletContext().getRealPath(filename);
updateNewsFile(realPath);
 
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(realPath)));
 
String s;
StringBuilder result = new StringBuilder();
while ((s = in.readLine()) != null) {
result.append(s);
}
in.close();
ModelAndView mv = new ModelAndView(this.view);
mv.addObject("feed", result.toString());
return mv;
}

Раз мы в коде видим ModelAndView - то ясно, что используется Spring MVC. Функция updateNewsFile(realPath) проверяет файл с фидами, и если его дата не равно сегодняшней, или файл вообще отсутствует, тащит фиды с блогспота, и пишет их в файл. Вот и ее код:

 
private static void updateNewsFile(String realPath) throws Exception {
Calendar today = Calendar.getInstance();
Calendar fileTime = Calendar.getInstance();
File file = new File(realPath);
boolean fileExists = true;
 
try {
fileTime.setTimeInMillis(file.lastModified());
} catch (Exception e) {
fileExists = false;
}
 
// if file doesn't exist or isn't up-to-date, refresh it
if (
!fileExists ||
(
today.get(Calendar.YEAR) != fileTime.get(Calendar.YEAR) ||
today.get(Calendar.MONTH) != fileTime.get(Calendar.MONTH) ||
today.get(Calendar.DATE) != fileTime.get(Calendar.DATE))
)
{
URL feed = new URL("http://jdevnotes.blogspot.com/feeds/posts/default");
BufferedReader in = new BufferedReader(new InputStreamReader(feed.openStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String s;
while ((s = in.readLine()) != null) Х
sb.append(s);
}
in.close();
writeContentToFile(realPath, sb.toString());
}
}


Функция writeContentToFile лочит файл и записывает в него содержимое фиды. Используется Java NIO. Пример использования я посмотрел вот по этой ссылке. Вот код функции:

private static void writeContentToFile(String path, String content) throws Exception {
FileOutputStream fos = null;
FileLock lock = null;
try {
fos = new FileOutputStream(path);
FileChannel fileChannel = fos.getChannel();
lock = fileChannel.tryLock();
if (lock != null) {
fos.write(content.getBytes());
}
} finally {
if (lock != null) {
lock.release();
}
fos.close();
}
}


Код простой и сам-себя-объясняет, т.е. self-explanatory =). Но есть одно "но". В примере используется RandomAccessFile. Сначала и я его использовал.

Это такой класс, который записывает строку как String, а не как байты. С этого я получил расход времени на задачу плюс 2.5 часа сверх обычного ;-) Уж как только я не "трахался" с этим - указывал явно кодировки при записи, явно при чтении, при записи и при чтении, и т.д., и т.п. Пока наконец не догадался заменить RandomAccessFile на FileOutputStream - после этого все заработало с первого раза.

Такие дела =)

суббота, 26 сентября 2009 г.

ExtJS - confirm window не показывается поверх остальных окон на десктопе

Проблема с ExtJS - на десктопе расположено несколько окон. Одно окно содержит панель со списком контактов. При удалении контакта надо выводить confirm window, т.е. подтверждать удаление. При этом, когда открыто одно окно, confirm window выводится нормально, т.е. поверх окна, блокируя все остальное. Если же на десктопе открыто несколько окон, то confirm window выводится позади них. Используется Firefox 3.0.14.

Причина:
Windowsmanager z-index равен по умолчанию 9000. Z-index остальных окон, которые добавляются к document.body, равен 9003.

Решение:
Уменьшить z-index группы окон, сделать его меньше, чем 9000.

var windows = new Ext.WindowGroup();
windows.zseed = 7000;


Пример:
Рассмотрим приложение, использующее десктоп, из комплекта примеров ExtJS. У меня на машине оно находится в папке D:\ext-3.0.0\examples\desktop. В GridWindow навесим обработчик на конпку "Add something":

Файл D:\ext-3.0.0\examples\desktop\sample.js:




tbar:[{
text:'Add Something',
tooltip:'Add a new row',
iconCls:'add',
handler: oops // this is OUR handler
}, '-', {
text:'Options',
tooltip:'Blah blah blah blaht',
iconCls:'option'
},'-',{
text:'Remove Something',
tooltip:'Remove the selected item',
iconCls:'remove'
}]

....

function oops() {
Ext.MessageBox.confirm('Add something', 'Do you really want add something?', function(btn) {
if (btn == 'yes') {
console.info('add smth');
} else {
console.info('do not add');
}
});
}


Если открыть только одно окно - GridWindow, то confirm ,удет показываться нормально - поверх него. Но если открыть еще дополнительное окно, то confirm показывается позади этих окон.

Теперь надо отредактировать файл D:\ext-3.0.0\examples\desktop\js\Desktop.js:



Ext.Desktop = function(app){
this.taskbar = new Ext.ux.TaskBar(app);
var taskbar = this.taskbar;

var desktopEl = Ext.get('x-desktop');
var taskbarEl = Ext.get('ux-taskbar');
var shortcuts = Ext.get('x-shortcuts');

var windows = new Ext.WindowGroup();
windows.zseed = 7000; // this is the KEY!!!!



Строкой

windows.zseed = 7000;

мы задаем стартовое значение z-index для всех окон группы (т.е. для всех окон десктопа). Т.к. задано значение меньше 9000, то это решает проблему.

См. также эту ссылку на форуме ExtJS.

пятница, 25 сентября 2009 г.

Перешел на новую работу

Перешел на новую работу, теперь работаю в компании EvaPhone. Очень доволен - классный коллектив, потрясающая атмосфера стартапа, интересные задачи. Ближайшее время буду заниматься JavaScript, так что, думаю, в блоге появятся посты на тему ДжаваСкрипта.

Smoke test

Smoke test - быстрое и грубое тестирование кода сразу после внесения в него правок. П поводу происхождения термина Википедия говорит следующее:

Первое свое применение этот термин получил у печников, которые, собрав печь, закрыв все заглушки, затапливали её и смотрели, чтобы дым шёл только из положенных мест.

Повторное «рождение» термина произошло в радиоэлектронике. Подключив в первый раз собранное устройство к источнику питания, радиолюбитель, пристально разглядывая каждый участок печатной платы, проводит так называемый «Smoke Test» — наблюдает, задымится или нет, потому что очень часто из-за досадных ошибок, допущенных при монтаже схемы, она оказывалась неработоспособна и отдельные её части выходили из строя из-за перегрева (часто с выделением дыма).

Еще одна версия (отсюда): все электронщики знают, что электронные приборы работают благодаря волшебному синему дыму, который находится внутри прибора. Иногда дым из прибора вылетает, и прибор перестает работать. Поэтому дымовой тест - тест, призванный проверить не улетучился ли дым.

Постоянные читатели