суббота, 14 июля 2012 г.

Разбор файла чертежа из SolidWorks 2007 и выше (заметки по MATERIALTREE)

Доброго времени суток.

Данный подход был не верен, так как выполняя код:
POIFSDocument doc = new POIFSDocument("MATERIALTREE", new FileInputStream(file))
я всегда получал сам файл, по это причине я его не мог раскрыть.


Чтение дерева материалов из файла описано в данном посте Чтение файла SolidWorks


Старая версия поста:
Заказчик поставил задачу  получать информацию из загруженных на сервер файлов чертежей SolidWorks.


Сделал предварительный обзор файлов SolidWorks, я выявил что они файлы 
базируются на OLE2.  Для работы с данным форматом файлов я использую http://poi.apache.org/

На сайте poi apache есть  простые примерчы как можно порчитать иформацию из файла.
При изучении содержимого файла, я натснулся на поле с именем "MATERIALTREE", мне зажотелось получить данные из этого поля, но тут то и были грабли....

Для начала, я не смог обратится простым способом так как DocumentInputStream и PropertySet мне отвечали NoPropertySetStreamException. Я нащел альтернативный подход к данному свойству: 
POIFSDocument doc = new POIFSDocument("MATERIALTREE", new FileInputStream(file))
 В результате мы получаем объект POIFSDocument который в себе содержет HexDump.
При разборе данного Hex-а:



        Object[] objs = doc.getViewableArray()
        Hex.decode(objs[0].toString())


Я получил примерно следующие:
00000000 D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 ................
00000010 00 00 00 00 00 00 00 00 3E 00 03 00 FE FF 09 00 ........>.......
00000020 06 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 ................
00000030 02 00 00 00 00 00 00 00 00 10 00 00 58 01 00 00 ............X...
00000040 03 00 00 00 FE FF FF FF 00 00 00 00 03 00 00 00
Потратив на разбор некоторое время, я наткнулся на сайт http://open-file.ru/, где по hex заголовку удалось выяснить данный hex может относится к :


ФорматТипОписание
.fpxРастровые изображенияФайл изображения FlashPix
HEXD0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00
.p65ИзображенияДокумент PageMaker 6.5
HEXD0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00
.pm6Размеченные документыДокумент PageMaker 6.0
HEXD0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00
.qxИсходный кодИсходный код Quexal
HEXD0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00


....




пока это все наблюдения по разбору POIFSDocument "MATERIALTREE"
to be continued...

пятница, 8 июня 2012 г.

Формат ответа сервиса в зависимости от запроса

Бывает необходимость в том что сервис возвращает разные результаты (xml, json, html) по одному адресу в зависимости от запроса.
Grails позволяет реализовать данную функциональность 2-мя способами.

  • Filters. В данной реализации необходимо наличия content-type в заголовке запроса;
  • AfterInterceptor. Реализация данного подхода возможна  в случаях если у вас в Config.groovy включена опция grails.mime.file.extensions = true.

Рассмотрим оба подхода.

Первый способ реализовать данную задачу с использованием фильтров. (http://grails.org/doc/latest/guide/single.html#filters). Подход позволяет пользоваться всеми прелестями Filtres в Grails. Реализуется данный подход через Content-type, что обязывает всегда указывать Content-Type, Grails распарсивает то что приходит в запросе и помещает content-type  в переменную format, объекта request.

class DetectFormatFilters {

    def filters = {
       all(action: '*') {
           after = { Map model ->
               switch (request.format) {
                   case 'html': println 'return HTML'; break;
                   case 'json': println 'return JSON'; break;
                   case 'xml': println 'return XML'; break;
               }
           }
       }
    }
}
P.S.: Типы указываются в Grails в config.groovy :
grails.mime.types = [ html: ['text/html','application/xhtml+xml'],
                     xml: ['text/xml', 'application/xml'],
                     text: 'text/plain',
                     js: 'text/javascript',
                     rss: 'application/rss+xml',
                     atom: 'application/atom+xml',
                     css: 'text/css',
                     csv: 'text/csv',
                     all: '*/*',
                     json: ['application/json','text/json'],
                     form: 'application/x-www-form-urlencoded',
                     multipartForm: 'multipart/form-data'
                   ]



Второй подход заключается в использовании интерсепротов внутри controller.
(http://grails.org/doc/latest/ref/Controllers/afterInterceptor.html)
Данный вариант позволяет использовать несколько вариантов запроса:
  • domain/Controller/action/.json, domain/Controller/action/.xml. Данный вариант работает в случае если настройка grails.mime.file.extensions установлена в  true;
  • domain/Controller/action/?format=json,  domain/Controller/action/?format=xml.
Необходимо в контролле добавить afterInterceptor,  он будет перехватывать результат action перед тем как сформировать ответ.

def afterInterceptor = {
       withFormat {
           html {println 'return HTML-1'}
           json {println 'return JSON-1'}
           js { println "alert('hello')-1" }
           xml { println 'return XML-1' }
       }
    }

withFormat позволяет перечислить типы ответа которые нам необходимы, если тип ответа не обнаружен в списке то будет взят первый пункт, рекомендуется первым пунктом указывать html.

четверг, 31 мая 2012 г.

Batch updates в Grails с использованием HQL

ScrollableResults scroll = getSession()
.createQuery("SELECT DISTINCT t FROM ${tableName} as t LEFT JOIN t.tags as tags WHERE tags.id in (:tags)")
.setParameterList("tags", [oldTag1.id, oldTag2.id])
.scroll(ScrollMode.FORWARD_ONLY) int count = 0;

 while (scroll.next()) {
  def exp = scroll.get(0)
  exp.tags.remove(oldTag1)
  exp.tags.remove(oldTag2)
  exp.tags.add(newTag)
  exp.save()
  if (++count % 20 == 0)
  {
    session.flush();
    session.clear(); }
  }

Для работы данного когда надо получить CurrentSession из SessionFactory.
Данный код выполняет HQL запрос и когда число строк обработанных в результате запроса без остатка делится на 20  то сессия хибернейта выполняет flush и clean, что позволяет не загружать память при больших запросах.

четверг, 26 мая 2011 г.

Обновление Fedora Core с 14 до 15 версии

Для обновления своей "Федоры" вам необходимо скачать пакет с репозитария

Fedora Core

fedora-release-15-1.noarch.rpm


Для пользователей Russian Fedora

rfremix-release-15-1.R.noarch.rpm


После скачивания, установите пакет:

Fedora Core

rpm -i fedora-release-15-1.noarch.rpm


Для пользователей Russiaon Fedora

rpm -i rfremix-release-15-1.R.noarch.rpm


После установки пакета вам необходимо отчистить репозитариии yum:

yum clean all



Теперь заветная команда:
yum update


и готовимся получать новые пакеты....


P.S.: Не всегда обновление проходит удачно.. ;) Удачи...

среда, 26 января 2011 г.

Гарантирует ли ORDER BY порядок вставки в таблицу?

Вопрос: Гарантирует ли ORDER BY порядок вставки в таблицу?
Ответ: нет не гарантирует

НО есть маленькая особенность, если таблица содержит поле IDENTITY(!!!)

Если перенос данных делать через

SELECT Col1, Col2, ID=IDENTITY (int, 1, 1)
INTO NewTable
FROM OldTable
Order By Col1

То в разных ситуация может получиться разная картина, и даже так:
Col1 Col2 ID
------- -------- --------
1 A 4
2 Z 2
7 G 5
11 F 3
17 I 1


Если вставку делать в таблицу, которая создана заранее и содержит поле IDENTITY, то вставка:

INSERT INTO NewTable (Col1, Col2) SELECT Col1, Col2 FROM OldTable ORDER BY Col1

ГАРАНТИРУЕТ, что поле идентити будет следовать согласно полю по которому идёт сортировка
ID (identity) Col1 Col2
------------- ------ ------
1 1 S
2 2 z
3 7 G
4 11 F
5 17 I


Но это не гарантирует, опять же, физический порядок вставки. Вся особенность в том, что во втором случае значения поля идентити генерятся ДО самой вставки на базе условия ORDER BY.

ЗЫ: Печально, что в BOL это не описано, точнее убого описано и споров в форумах на эту тему нашёл больше, чем рассчитывал.

Ссылки по теме:
http://blogs.msdn.com/b/sqltips/archive/2005/07/20/441053.aspx
http://support.microsoft.com/kb/273586/en-us/
Спасибо Алексею Князеву за предоставленую информацию.

пятница, 21 января 2011 г.

Удаление дублей в таблице без первичных ключей

Задача:
Необходимо одним запросом удалить дублирующийся строки в таблице, записи в которой не имеют уникальных ключей

Решение:
WITH cte
AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY id ORDER BY name) id, * FROM table
)
DELETE FROM cte WHERE id > 1

P.S.: Данное решение возможно только на MS SQL серверах выше 2000 версии

понедельник, 29 ноября 2010 г.

Лекции по Системам реального времени

Отсканированные лекции по Системам реального времени, готовимся к зачету =)
P.S.: Спасибо Игорю Мартемьянову

Леции