Сегодня в очередной раз хочу вернуться к теме визуализации данных Oracle BI на географической карте.
Тема эта в моем блоге мусолилась часто: BIEE 11g: Mapviewer + OpenStreetMap, BIEE11g: Mapviewer + OpenStreetMap как WMS + HttpProxy, BIEE 11g: WriteBack на карте
Но мне все равно есть что рассказать нового - как показывать в качестве фоновой карты картинки-ячейки мозаичной карты от LGPL-ресурса OpenStreetMap Mapnik.
Зачем это нужно?
Чтобы показывать в BI "красивые карты" с графической информацией о морях, реках, дорогах, рельефом местности, городами и т.д.
Все то, к чему мы привыкли, используя общедоступные картографические ресурсы (Google Maps, Yandex Maps etc). Если не использовать подгрузку этих внешних данных в виде картинок, то придется хранить в БД Oracle в виде SDO_GEOMETRY все привычные пользователям геометрии ("и тропинку, и лесок"), откуда-то брать эти данные, поддерживать в актуальном виде, и визуализировать с помощью mapviewer, нагружая его отрисовкой множества геометрических слоев, не связанных непосредственно с задачами аналитики в BI.
Но у нас уже настроена подгрузка фоновой карты в javascript-функциях
Да, и я сам описывал как это сделать в сообщении BIEE 11g: Mapviewer + OpenStreetMap. Но минус этого решения в том, что для отображения карты в браузере пользователя необходимо подключение к интернету. Также следует понимать, что при работе сотни пользователей с аналитическим отчетом в BI, данные которого визуализируются на карте, каждый пользователь будет скачивать из интернета одни и те же картинки-ячейки, увеличивая интернет-трафик.
Но разве не эта же проблема была решена в сообщении BIEE11g: Mapviewer + OpenStreetMap как WMS + HttpProxy
Да, именно. Вот только там есть ряд неточностей, связанных с тем, что WMS (web map service) ресурсы с данными OpenStreetMap периодически меняют свои адреса - http://wiki.openstreetmap.org/wiki/WMS. А также неприятность в том, что эти WMS ресурсы содержат не очень подробные данные по России. Гораздо более качественная, подробная и красивая картинка получается при работе с OSM Mapnik.
Итак, создадим новую фоновую карту в интерфейсе Oracle Mapviewer.
Тип карты - EXTERNAL
Прежде чем двигаться дальше - нужно скопировать в файловую систему сервера BI jar-архив mvadapter.jar. Этот jar-архив содержит скомпилированный java-класс, реализующий логику загрузки картинок-ячеек OSM Mapnik (код класс будет далее).
Указываем основные свойства карты
Name - OSM_MAPNIK
Data source - доступный в вашей настройке mapviewer
Map service Url - http://tile.openstreetmap.org/
Adapter class - mcsadapter.OSMMapnikAdapter
Jar file location - укажите путь в файловой системе сервера BI до mvadapter.jar (см. предыдущий шаг)
Tile storage - укажите путь в файловой системе до каталога, где будет храниться кеш всех картинок-ячеек мозаичной карты
Zoom levels - 1
Остальные свойства оставьте без изменений.
Сохраняем новую фоновую карту
SQL-запросом к БД, на которую настроен mapviewer, проверяем наличие созданной карты и значение поля DEFINITION
select t.rowid, t.* from USER_SDO_CACHED_MAPS t where t.NAME = 'OSM_MAPNIK'
Но итоговое определение карты должно быть таким:
update USER_SDO_CACHED_MAPS tНеобходимость этого шага обусловлена тем, что в веб-интерфейсе mapviewer нельзя задать важное свойство fetch_larger_tiles="false", а также сложностью ручного определения всех уровней детализации.
set t.DEFINITION =
'<map_tile_layer name="OSM_MAPNIK" http_header_expires="168.0" image_format="PNG" fetch_larger_tiles="false">
<external_map_source url="http://tile.openstreetmap.org/" request_method="GET" adapter_class="mcsadapter.OSMMapnikAdapter" transparent="false"/>
<tile_storage root_path="/u02/Middleware/Oracle_BI1/bifoundation/jee/mapviewer.ear/web.war/WEB-INF/tilecache/SUPERMAG.OSM_MAPNIK"/>
<coordinate_system srid="3785" minX="-2.0037508E7" maxX="2.0037508E7" minY="-2.0037508E7" maxY="2.0037508E7"/>
<tile_image width="256" height="256"/>
<zoom_levels levels="20" min_scale="0.0" max_scale="0.0" min_tile_width="76.43702697753906" max_tile_width="4.00750166855785E7">
<zoom_level level="0" name="" description="" scale="0.0" tile_width="4.00750166855785E7" tile_height="4.00750166855785E7"/>
<zoom_level level="1" name="" description="" scale="0.0" tile_width="2.0037508E7" tile_height="2.0037508E7"/>
<zoom_level level="2" name="" description="" scale="0.0" tile_width="1.0018754E7" tile_height="1.0018754E7"/>
<zoom_level level="3" name="" description="" scale="0.0" tile_width="5009377.0" tile_height="5009377.0"/>
<zoom_level level="4" name="" description="" scale="0.0" tile_width="2504688.5" tile_height="2504688.5"/>
<zoom_level level="5" name="" description="" scale="0.0" tile_width="1252344.25" tile_height="1252344.25"/>
<zoom_level level="6" name="" description="" scale="0.0" tile_width="626172.125" tile_height="626172.125"/>
<zoom_level level="7" name="" description="" scale="0.0" tile_width="313086.0625" tile_height="313086.0625"/>
<zoom_level level="8" name="" description="" scale="0.0" tile_width="156543.03125" tile_height="156543.03125"/>
<zoom_level level="9" name="" description="" scale="0.0" tile_width="78271.515625" tile_height="78271.515625"/>
<zoom_level level="10" name="" description="" scale="0.0" tile_width="39135.7578125" tile_height="39135.7578125"/>
<zoom_level level="11" name="" description="" scale="0.0" tile_width="19567.87890625" tile_height="19567.87890625"/>
<zoom_level level="12" name="" description="" scale="0.0" tile_width="9783.939453125" tile_height="9783.939453125"/>
<zoom_level level="13" name="" description="" scale="0.0" tile_width="4891.9697265625" tile_height="4891.9697265625"/>
<zoom_level level="14" name="" description="" scale="0.0" tile_width="2445.98486328125" tile_height="2445.98486328125"/>
<zoom_level level="15" name="" description="" scale="0.0" tile_width="1222.992431640625" tile_height="1222.992431640625"/>
<zoom_level level="16" name="" description="" scale="0.0" tile_width="611.4962158203125" tile_height="611.4962158203125"/>
<zoom_level level="17" name="" description="" scale="0.0" tile_width="305.74810791015625" tile_height="305.74810791015625"/>
<zoom_level level="18" name="" description="" scale="0.0" tile_width="152.87405395507812" tile_height="152.87405395507812"/>
<zoom_level level="19" name="" description="" scale="0.0" tile_width="76.43702697753906" tile_height="76.43702697753906"/>
</zoom_levels>
</map_tile_layer>'
where t.NAME = 'OSM_MAPNIK'
Выполняем обновление определения карты. И проверяем что изменилось в веб-интерфейсе mapviewer.
При попытке посмотреть превью карты, скорее всего, появится следующая ошибка
Для ее устранения необходимо в файле weblogic.xml раскомментировать узел library-ref для библиотеки jstl 1.2
После необходимо обязательно рестартовать приложение mapviewer через консоль WLS
И тогда превью карты будет работать без ошибок
Вот так будет выглядеть созданная фоновая карта в режиме настройки метаданных Oracle BI.
А вот так будет выглядить директория с кешируемыми картинками мозаичной карты
Содержимое подпапки 1 уровня детализации
И сами картинки-ячейки 1 уровня детализации
Теперь пользователи при работе с анализами BI, содержащими визуализацию на карте, будут получать данные из общего кеша, а не из интернета.
И напоследок - код класса, реализующего подгрузку tile-ячеек:
package mcsadapter;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Logger;
import oracle.lbs.mapserver.core.OMSException;
import oracle.mapviewer.share.mapcache.MapSourceAdapter;
import oracle.mapviewer.share.mapcache.TileDefinition;
import oracle.mapviewer.share.util.LogFactory;
public class OSMMapnikAdapter extends MapSourceAdapter {
private static Logger log;
static {
log = LogFactory.getLogger(oracle.mapviewer.share.util.LogFactory.LoggerEnum.SHARE);
}
public OSMMapnikAdapter() {
}
public String getMapTileRequest(TileDefinition tile) {
int zoomLevel = tile.getZoomLevel();
long mX = tile.getMeshX();
long mY = (long)Math.pow(2, zoomLevel) - (long)tile.getMeshY() - 1;
return (new StringBuilder()).
append(Integer.toString(zoomLevel)).
append("/").append(Long.toString(mX)).
append("/").append(Long.toString(mY)).
append(".png").toString();
}
public byte[] getTileImageBytes(TileDefinition tiledefinition) throws Exception {
String tileRequest = this.getMapServiceURL() + getMapTileRequest(tiledefinition);
log.finer("XX_CUSTOM: " + tileRequest);
Proxy proxy = null;
boolean proxyFlag = "NONE".equalsIgnoreCase(getProxyHost());
if (getProxyHost() != null && !proxyFlag) {
InetSocketAddress inetsocketaddress = new InetSocketAddress(this.getProxyHost(), this.getProxyPort());
proxy = new Proxy(java.net.Proxy.Type.HTTP, inetsocketaddress);
}
BufferedInputStream bufferedinputstream = null;
byte tileBytes[];
try {
URL url = new URL(tileRequest);
URLConnection urlconnection = proxy == null ? proxyFlag ? url.openConnection(Proxy.NO_PROXY) : url.openConnection() : url.openConnection(proxy);
urlconnection.setConnectTimeout(this.getConnectionTimeout());
urlconnection.connect();
bufferedinputstream = new BufferedInputStream(urlconnection.getInputStream());
tileBytes = toBytes(bufferedinputstream);
bufferedinputstream.close();
bufferedinputstream = null;
}
catch(Exception exception) {
throw new Exception("Failed to fetch external map tile.", exception);
}
finally {
try {
if(bufferedinputstream != null) {
bufferedinputstream.close();
bufferedinputstream = null;
}
}
catch(IOException ioexception1) {
throw ioexception1;
}
}
return tileBytes;
}
private byte[] toBytes(BufferedInputStream bufferedinputstream) throws OMSException {
ByteArrayOutputStream bytearrayoutputstream = null;
try {
bytearrayoutputstream = new ByteArrayOutputStream();
byte abyte0[] = new byte[2048];
for (int i = 0; 0 < (i = bufferedinputstream.read(abyte0));)
bytearrayoutputstream.write(abyte0, 0, i);
bytearrayoutputstream.close();
}
catch(IOException ioexception) {
throw new OMSException(ioexception);
}
return bytearrayoutputstream.toByteArray();
}
}
P.S. Что делать если на сервере с Oracle BI нет прямого доступа в интернет. Например, он доступен через корпоративную HTTP-прокси с аутентификацией. В этом случае рекомендую внимательно прочитать мою прошлу статью - BIEE11g: Mapviewer + OpenStreetMap как WMS + HttpProxy
Ждем продолжений в стиле "BIEE11g: Mapviewer + локальный тайл сервер на базе ......?".
ОтветитьУдалитьОгромное Вам Спасибо за полезную информацию!
Пожалуйста!
ОтветитьУдалитьРад что кому-то полезны мои статьи.