Object Pascal для Java и Android

На прошедшей в Лас-Вегасе конференции Developer Solutions Conference, компания RemObjects Software впервые представила свой новый проект - «Cooper«. Cooper - это новый компилятор языка RemObjects Oxygene для платформ Java и Android (RemObjects Oxygene - это реализация языка Object Pascal для .NET и Mono, третья версия которого была выпущена как Embarcadero Delphi Prism). Cooper подключает стандартные библиотеки Java-классов и создает 100% байт-код для виртуальных машин Java и Dalvik (Dalvik - виртуальная машина Java для Android).
В ролике показано, как под Mac-OS в командной строке скомпилировали паскалевский код консольной программы и калькулятора, использующего swing-контролы, а затем запустили полученные jar-файлы.

Планируется интеграция Cooper в Visual Studio и MonoDevelop (аналогично с компилятором для .NET). Обещают выпустить это чудо уже в этом году.

Читать на сайте автора.

Сохранение в базу данных отчета FastReport в формате PDF

Недавно пришлось писать DLL, одна из функций которой должна была:

1. сформировать отчет в FastReport;
2. экспортировать отчет в файл PDF-формата и сохранить его в базе данных;
3. возвратить идентификатор сохраненного в базе данных файла.

Предположим, что исходная структура таблицы для хранения файла в базе данных была такая (MS SQLServer 2000):

CREATE TABLE X.FILES (
ID BIGINT IDENTITY NOT NULL,
FILE_BODY IMAGE NULL,
CONSTRAINT PK_FILES PRIMARY KEY (ID)),

где FILE_BODY - это поле, в которое сохраняется файл, а ID - идентификатор файла.
Для начала я создал процедуру, которая будет вставлять файл в базу данных и возвращать идентификатор вставленного файла.

CREATE PROCEDURE X.InsertFile
@FILE image,
@ID bigint OUTPUT
AS
INSERT INTO X.FILES(FILE_BODY) VALUES(@FILE)
SET @ID = SCOPE_IDENTITY()
GO

Потом сел писать код DLL. В Delphi вся работа с файлами реализована с помощью потоков, поэтому я немного удивился, когда оказалось, что метод Export у TfrxReport экспортирует отчет только в файл (честно сказать, я ожидал увидеть, что-то в стиле ExportToStream). Т.е. вместо прямой передачи отчета через поток в базу данных, необходимо было сначала сохранить отчет во временный файл, а потом этот файл загрузить в базу данных. Мне это не понравилось, т.к. файловые операции (сначала записи, потом чтения) должны были хоть немного, но тормозить работу. Но нужно было срочно отдать DLL, поэтому я не стал разбираться с экспортом и сделал через файл:


db: TSDDatabase; // база данных SQLDirect
spInsertFile: TSDStoredProc; // вызов X.InsertFile
frxReport: TfrxReport;
frxPDFExport: TfrxPDFExport;

Function GetDoc(const sDotName: String; …): Integer;
begin
Result := -1;
// загружаем шаблон отчета
If frxReport.LoadFromFile(sDotName)
then begin
// устанавливаем параметры отчета

If frxReport.PrepareReport
then try
// получаем имя временного файла
frxPDFExport.FileName := GetTempFileName;
Try
// экспортируем отчет во временный файл
frxReport.Export(frxPDFExport);
// загружаем PDF-файл в параметр процедуры
// из временного файла
spInsertFile.Params[1].LoadFromFile(frxPDFExport.FileName, ftBlob);
Except
on E: Exception do
WriteErrorMessage(E.Message);
End;
// сохраняем PDF-файл в базу данных
Try
db.StartTransaction;
spInsertFile.ExecProc;
db.Commit;
Result := spInsertFile.Params[2].AsInteger;
Except
on E: ESDEngineError do
begin
db.Rollback;
WriteErrorMessage(E.Message);
end;
End;
Finally
// удаляем временный файл
DeleteFile(frxPDFExport.FileName)
End
else WriteErrorMessage(‘Ошибка подготовки отчета’)
end
else WriteErrorMessage(‘Файл шаблона не найден’)
end;

После передачи DLL другому программисту, мысли о лишних файловых операциях при сохранении отчета в базу через временный файл, не давала мне покоя. Вечером, не найдя решения в документации по FastReport, я, прежде чем смотреть исходный код экспорта, решил еще раз пройтись по методам и свойствам экспорта. Глаз сразу же зацепился за свойство Stream. Я создал для этого свойства поток и метод Export у TfrxReport выгрузил отчет не в файл, а в поток.

Function GetDoc(const sDotName: String; …): Integer;
begin
Result := -1;
// загружаем шаблон отчета
If frxReport.LoadFromFile(sDotName)
then begin
// устанавливаем параметры отчета

If frxReport.PrepareReport
then begin
Try
Try
// создаём поток в памяти
frxPDFExport.Stream := TMemoryStream.Create;
// экспортируем отчет в поток
frxReport.Export(frxPDFExport);
// загружаем PDF-файл в параметр процедуры
// из потока в памяти
spInsertFile.Params[1].LoadFromStream(frxPDFExport.Stream, ftBlob);
Except
on E: Exception do
WriteErrorMessage(E.Message);
End;
Finally
frxPDFExport.Stream.Free;
End;
// сохраняем PDF-файл в базу данных
Try
db.StartTransaction;
spInsertFile.ExecProc;
db.Commit;
Result := spInsertFile.Params[2].AsInteger;
Except
on E: ESDEngineError do
begin
db.Rollback;
WriteErrorMessage(E.Message);
end;
End;
end
else WriteErrorMessage(‘Ошибка подготовки отчета’)
end
else WriteErrorMessage(‘Файл шаблона не найден’)
end;

Часто решение задачи лежит на поверхности и нет нужды копаться в чужом коде. Нужно лишь быть внимательным и никогда не сдавайтесь - «ищите и обрящите».

Читать на сайте автора.