logo

22 дек. 2009 г.

BIP: относительные пути вызова суб-шаблонов разметки

В BI Publisher есть довольно удобная возможность модульного создания шаблонов разметки. Если во всех ваших отчетах «шапка» и «подвал» одинаковы, то есть смысл вынести их в суб-шаблоны. А в самих отчетах оставить лишь ссылки на них. Преимущества очевидны.
Также суб-шаблоны могут быть полезны как хранилище XSL-функций (например, функции по преобразованию числа в представление прописью)

Все это прекрасно, но существует небольшое «ограничение». Якобы, данный метод работает только с абсолютными путями.


Для примера создадим файл основного шаблона и файл суб-шаблона. Поместим их в корень диска D.




Все работает замечательно, но если убрать абсолютный путь, то:


Разберемся подробнее.
Воспользуемся возможностью выгрузки RTF-шаблона в XSL-FO представление из встроенного в MSWord плагина.


Подгрузка дочерних шаблонов происходит за счет инструкции XSLT-процессору с указанием ссылки на файл. Причем используется фиктивный протокол «rtf2xsl».


Обработка этой инструкции производится в классе «MemURLConnection».

Произведем небольшое изменение исходного кода класса (получен с помощью jad) – добавим логгирование текущего пути JVM.

package oracle.apps.xdo.template.rtf.net;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.Hashtable;
import java.util.StringTokenizer;
import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.xdo.XDOException;
import oracle.apps.xdo.template.rtf.RTF2XSLParser;
/*импорт логгера*/
import oracle.apps.xdo.common.log.Logger;

public class MemURLConnection extends URLConnection
{

public MemURLConnection(URL url)
{
super(url);
mUrl = null;
mParameters = new Hashtable(5);
mUrl = url;
}

public String getContentType()
{
return "text/xml";
}

public InputStream getInputStream()
throws IOException
{

/*вывод информации в лог*/
File f = new File(".");
String path = f.getCanonicalPath();
Logger.log(this, "XXX path: "+path, 1);

String s = String.valueOf(mUrl);
int i = s.indexOf("?");
if(i > 0)
parseRequestParameters(mParameters, s.substring(i + 1, s.length()));
s = s.substring(0, i);
i = s.indexOf("_");
URL url = new URL((new StringBuilder()).append(s.substring("rtf2xsl".length() + 3, i)).append(":").append(s.substring(i + 1, s.length())).toString());
try
{
RTF2XSLParser rtf2xslparser = new RTF2XSLParser();
rtf2xslparser.setSequenceID((String)mParameters.get("sid"));
String s1 = (String)mParameters.get("eaf");
int j = 1;
if(s1 != null)
try
{
j = Integer.parseInt(s1);
if(j == 2)
j = 3;
}
catch(Exception exception) { }
rtf2xslparser.setExtractAttributes(j);
rtf2xslparser.generateXSL(url.openConnection().getInputStream());
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(16384);
PrintWriter printwriter = new PrintWriter(new OutputStreamWriter(bytearrayoutputstream, "utf-8"));
rtf2xslparser.writeFO(printwriter);
printwriter.close();
byte abyte0[] = bytearrayoutputstream.toByteArray();
return new ByteArrayInputStream(abyte0);
}
catch(XDOException xdoexception)
{
throw new IOException(xdoexception.getMessage());
}
catch(IOException ioexception)
{
throw ioexception;
}

}

protected static final void parseRequestParameters(Hashtable hashtable, String s)
{
StringTokenizer stringtokenizer = new StringTokenizer(s, "&");
do
{
if(!stringtokenizer.hasMoreTokens())
break;
String s1 = stringtokenizer.nextToken();
int i = s1.indexOf("=");
if(i > 0 && i < s1.length())
{
String s2 = s1.substring(0, i);
String s3 = s1.substring(i + 1, s1.length());
hashtable.put(s2, s3);
}
} while(true);
}

public void connect()
throws IOException
{
}

public static final String RCS_ID = "$Header: /export/home/mktdev/cvsroot/ej/java/rtf/net/MemURLConnection.java,v 1.7 2005/04/23 05:32:19 xin.jiang Exp $";
public static final boolean RCS_ID_RECORDED = VersionInfo.recordClassVersion("$Header: /export/home/mktdev/cvsroot/ej/java/rtf/net/MemURLConnection.java,v 1.7 2005/04/23 05:32:19 xin.jiang Exp $", "oracle.apps.xdo.template.rtf.net");
public static final String PROTOCOL = "rtf2xsl";
protected static Hashtable mStreamCache = new Hashtable(20);
URL mUrl;
protected Hashtable mParameters;

}


Скомпилируем класс (не забываем в classpath указать пути до основных jar-библиотек BIP) и наглейшим образом подменим стандартный класс нашим.
Привожу пример для инсталляции BIP в базовом режиме (только на OC4J).
OC4J должен быть остановлен.


Стартуем OC4J. Создаем новый отчет, использующий суб-шаблон без абсолютного пути. Запускаем его и получаем ошибку.
Далее смотрим лог (если вы еще не знаете как включать логгирование BIP - тынц)


Вот и каталог, относительно которого будут вычислять относительные пути. Догадаться было несложно – ведь JVM для BIP мы стартуем именно оттуда – но теперь мы убедились окончательно.

Поправим наш основной шаблон. Загрузим его в BIP.


Не забываем сконфигурировать отчет – убираем запрет на внешние ссылки.


Вуаля!

Комментариев нет:

Отправить комментарий