O IBM Mashup Center vem com geradores de feed que podem acessar e gerar feeds XML diretamente a partir de origens de dados corporativos. Ao mesmo tempo, devido à diversidade de armazenamentos de dados e de software, haverá origens de dados que não podem ser acessadas por estes geradores incorporados. Para permitir o aumento da capacidade do IBM Mashup Center, a capacidade de geração de feeds pode ser estendida através da inclusão de plug-ins.
Este artigo é uma sequência para o artigo " Estenda a abrangência de dados para IBM Mashup Center" e é baseado na V1.1 do software. Ele assume que você já está familiarizado com os fundamentos de escrita de plug-ins do IBM Mashup Center. Em particular, você deve saber como programar em Java™, JSP e JavaScript. O artigo mostra como desenvolver um plug-in para converter HTML em XML e usa este exemplo para ilustrar a escrita de um plug-in mais complexo. Como um benefício colateral, depois do HTML estar no formato XML, ele pode ser lido no Feed Mashup Editor, permitindo a extração de dados.
Ferramentas para conversão de HTML em XML
Precisamos de um pacote Java que converterá HTML em XML. Há uma série de pacotes Java. Este projeto usa JTidy, um conjunto Java do HTML Tidy do W3C. O HTML Tidy começou como um verificador de sintaxe HTML e uma impressora sofisticada. Como seu primo não-Java, o JTidy pode ser usado como uma ferramenta para limpeza malformada e HTML falho. Ele suporta, além disso, a geração de XML. Você encontrará um link na seção Recursos para fazer o download e instale o JTidy.
Você usará o Tidy.jar na pasta build. Para tornar o JAR autocontido, ele contém uma versão anterior das classes do DOM (Document Object Model) da W3C. Como as versões mais recentes das classes do DOM do W3C agora estão incluídas no JDK, as classes a partir do pacoteorg.w3c.dom devem ser removidas.
Configurando um Projeto Eclipse
Como descrito na Seção 6.1 da Referência da Interface de Programação de Aplicativos, Versão 1.0, a estrutura de geração de feeds automaticamente procura por arquivos ZIP contendo plug-ins de terceiros colocados na pasta especial <WebApplication>/WEB-INF/plugins. O archive ZIP deve ter a estrutura de pasta especificada a seguir:
- /client/plugins/PLUGIN_DIR -- Contém arquivos para navegadores, como imagens, arquivos JavaScript e assim por diante.
- /server/plugins/PLUGIN_DIR -- Contém os arquivos usados pelo plug-in para renderizar a si próprio (arquivos HTML, páginas JSP). Pastas adicionais para arquivos de plug-in podem estar incluídas.
- /WEB-INF/classes -- Contém classes Java do plug-in. Isto pode ser uma hierarquia de pastas. As classes serão copiadas para <WebApplication>/WEB-INF/classes.
- /WEB-INF/lib -- Contém arquivos JAR usados pelo plug-in (de terceiro).
Para simplificar a construção final e o empacotamento do plug-in, você pode desejar criar um projeto usando seu IDE favorito com a mesma estrutura de diretórios conforme exigido pelo archieve ZIP final. A Figura 1 mostra o layout do projeto Eclipse criado pelo autor.
Figura 1. Projeto Eclipse
Observe que o PLUGIN_DIR deve ser exclusivo e ter o mesmo nome do pacote do plug-in. Para este exemplo, eu usei o nome do pacote sample.mashupcenter.tidyhtml. Observe também que colocamos o Tidy.jar na pasta WEB-INF/lib e criamos uma pasta chamada lib_noship contendo dois JARs adicionais que são fornecidos pelo servidor Mashup Center durante o tempo de execução mas não estão disponíveis no ambiente de desenvolvimento. Estes JARs não deve estar incluídos no arquivo ZIP da implementação final. De fato, o carregamento do arquivo ZIP do plug-in poderia falhar se eles fossem incluídos por erro.
cada plug-in do Mashup Center possui duas operações principais: um editor para coletar os parâmetros de criação e um gerador para criar o feed. Feed normalmente se refere a um documento XML de acordo com a especificação RSS ou ATOM. Observe que neste caso, o XML gerado originará a partir do HTML e estará de acordo com a especificação RSS ou ATOM. A estrutura do plug-in descobre quais classes Java implementam as duas operações principais lendo o arquivo package.xml, que deve ser colocado na pasta server/plugins/PLUGIN_DIR. A Lista 1 mostra o arquivo package.xml para este plug-in.
Lista 1. Arquivo de pacote XML
<plugin> <name>Tidy Html</name> <author>L. Mau</author> <version>1.0</version> <category>departmental</category> <editor>Html2XmlEditorPlugin</editor> <generator>Html2XmlGeneratorPlugin</generator> <description>converte qualquer página HTML em XHTML</description> <icon16path>/plugins/sample.mashupcenter.tidyhtml/icons/btn16_hello.gif</ icon16path> <icon32path>/plugins/sample.mashupcenter.tidyhtml/icons/btn32_hello.gif</ icon32path> <icon64path>/plugins/sample.mashupcenter.tidyhtml/icons/btn64_hello.gif</ icon64path> <objectType>feed</objectType> </plugin> |
É importante mencionar que os elementos nome, descrição e versão são para benefício do criador e não use a estrutura do plug-in do IBM Mashup Center. A estrutura do plug-in usa as propriedades plugin.uiname dentro do arquivo ui.properties como o nome do plug-in quando apresenta a lista das opções após os usuários selecionarem Novo Feed.
O arquivo ui.properties reside na pasta /server/plugins/PLUGIN_DIR/nls e é carregado usando a convenção de carregamento do pacote de recursos Java padrão. Para cada idioma suportado, coloque a cadeia traduzida para plugin.name em um arquivo de propriedades com o código do idioma anexado à "ui." Por exemplo, a versão japonesa do arquivo deve ser nomeada como ui_ja.properties.
O Html2XmlEditorPlugin estende BaseEditorPlugin, uma classe base que nos exige implementar o método renderEditor.
Lista 2. Classe Html2XmlEditorPlugin
package sample.mashupcenter.tidyhtml;
import : : : : : // omitido da listagem
/**
* Este plug-in usa o JTidy para converter de HTML para XML.
*/
public class Html2XmlEditorPlugin extends BaseEditorPlugin {
private static final Log log = LogFactory.getLog(Html2XmlEditorPlugin.class);
public static final String I18N_RESFILE = Html2XmlConstants.PLUGIN_NAME
+ ".nls.tidyhtml";
public static final String HTTP_BASEURL = "plugins/"
+ Html2XmlConstants.PLUGIN_NAME + "/";
public static final String RES_BASEURL = "/" + HTTP_BASEURL;
public static final String HELPPATH = HTTP_BASEURL + "help/tidyhtml.htm";
|
A primeira instrução na classe cria uma instância do log estático a partir do pacote de registro comum do Apache. Esta é a mesma estrutura de registro que a usada pela infraestrutura de geração de feeds. As mensagens de log serão interpostas por aquelas da estrutura de geração de feeds e serão gravadas no arquivo <WebApplication>/META-INF/logs/javamashuphub.log a seguir. Pelo padrão, somente mensagens do WARN e acima (por exemplo ERROR) serão gravadas no arquivo de log.
A próxima instrução é a constante da cadeia para um arquivo de recursos. Mesmo se não houver necessidade de traduzir todas as constantes da para diferentes idiomas, é uma boa prática de programação manter todas as cadeias de texto exibidas pela interface com o usuário em um arquivo de recursos separado. Observe que o arquivo tidyhtml.properties está colocado no mesmo diretório que o arquivo ui.properties descrito anteriormente.
As últimas poucas constantes da cadeia definem os caminhos para vários recursos necessários pelo plug-in. Observe que o local do tempo de execução destes recursos imitam a estrutura do arquivo ZIP do plug-in.
O método renderEditor usa dois parâmetros: RequestData e Entry. Este método é chamado pela estrutura quando os usuários selecionam criar um novo feed usando este plug-in, ou quando os usuários editam um feed existente, anteriormente criado por este plug-in. Como veremos, o método usar dois parâmetros de tipos RequestData e Entry. Os dois parâmetros são realmente comuns a todos os métodos chamados pela estrutura na resposta às ações do usuário. O RequestData contém informações enviadas a partir do navegador e Entry contém todas as informações mantidas pela estrutura para esta instância do feed.
Lista 3. Corpo do método renderEditor
public ViewBean renderEditor(RequestData rdata, Entry entry)
{
ResourceBundle i18n = ResourceBundle.getBundle(I18N_RESFILE,rdata.getLocale());
String pluginId = this.getId();
Html2XmlUrlViewBean htViewBean = new Html2XmlUrlViewBean();
htViewBean.setEntry(entry);
htViewBean.setHtmlUrl( entry.getAttribute(Html2XmlUrlViewBean.PARAM_HTMLURL ) );
htViewBean.setSnapshot( entry.getAttribute(Html2XmlUrlViewBean.PARAM_SNAPSHOT ) );
FormViewBean form = new FormViewBean();
form.setSuffix( htViewBean.getSuffix() );
form.addComponent( htViewBean );
form.setOnsubmit( PluginHelper.getClientMe(pluginId, entry.getObjectId()) +
".invokeServer('displayHtmlPage'," +
PluginHelper.getClientId(pluginId, entry.getObjectId()) +
"_" + form.getSuffix() + ");");
form.setEntry(entry);
FrameViewBean frame = new FrameViewBean();
frame.addComponent(form);
frame.setLabel(entry.getTitle());
frame.setTitle(i18n.getString("frame.urltitle"));
frame.setEntry(entry);
frame.setHelpPath( HELPPATH );
return frame;
}
|
O método retorna uma instância de tipo ViewBean. ViewBean é similar ao Java Bean com getters e setters para propriedades de exibição. Sua principal finalidade é especificar o JSP usado pela estrutura de geração de feeds para criar HTML para o editor específico do plug-in. Como o método renderEditor não pode ser chamado para editar uma instância existente, ele recupera todos os dados salvos anteriormente para esta instância chamando o método Entry::getAttribute. Veremos posteriormente quando e como estes dados são salvos. O valor recuperado é então passado para o Html2XmlUrlViewBean para que o JSP associado possa exibir o valor anteriormente fornecido pelo usuário. Observe que o Html2XmlViewBean específico do plug-in não é retornado diretamente, mas em vez disso é quebrado dentro da instância FormViewBean através do método addComponent. O FormViewBean fornece a lógica JavaScript customizada para enviar as informações digitadas pelo usuário para o plug-in quando o botão Avançar na interface do editor do tipo assistente é clicado. Finalmente, o FormViewBean é então quebrado dentro de um FrameViewBean. Ele é o mais recente retornado.
Um última observação antes de movê-lo. Chamamos o método setOnsubmit para fornecer a parte do código JavaScript para executar quando o botão Avançar for clicado. O código JavaScript chama a função invokeServer do hub.managers.InvokePlugin descrita na Seção 6.3.2 da Referência da Interface de Programação de Aplicativos. O primeiro parâmetro especifica o método displayHtmlPage nesta classe que será usada para servir a próxima página do editor.
Html2XmlUrlViewBean e sue arquivo JSP associado
Já descrevemos brevemente o Html2XmlUrlViewBean na seção anterior. A Lista 4 mostra parte da definição de classe:
Lista 4. Html2XmlUrlViewBean
public class Html2XmlUrlViewBean extends ViewBean
{
public static final String PARAM_HTMLURL = "htmlurl";
public static final String PARAM_SNAPSHOT = "snapshot";
private String htmlUrl;
private String snapshot;
public Html2XmlUrlViewBean()
{
this.setI18NProperties( Html2XmlConstants.PLUGIN_NAME + ".nls.tidyhtml");
}
/* (non-Javadoc)
* @see com.ibm.mashuphub.model.ViewBean#getJSPPath()
*/
@Override
public String getJSPPath() {
return "/server/plugins/" + Html2XmlConstants.PLUGIN_NAME + "/tidyhtmlUrl.jsp";
}
public String getSuffix() {
return "tidyhtmlUrl";
}
|
O método getJSPPath será chamado pelo FormViewBean quando ele tentar gerar o formulário HTML para reunião destes parâmetros específicos do plug-in. O método getSuffix deve retornar uma cadeia exclusiva entre os diversos ViewBeans deste plug-in. Antes de procurar no arquivo JSP associado, ele ajuda primeiro a procurar no formulário HTML renderizado:
Figura 2. Primeira página do editor InfoSphere MashupHug
Observe que o formulário possui dois elementos de entrada:
- Um campo de texto para coleta da URL para HTML que o usuário deseja converter para XML e
- Uma caixa de opção para indicar que iremos salvar o XML gerado na primeira chamada e simplesmente retornará o XML nos pedidos de geração de feeds subsequentes. Isto é adequado quando a página HTML for estática e raramente muda.
Agora que vimos o que deve ser gerado, é muito mais fácil entender o arquivo JSP.
Lista 5. tidyhtmlUrl.jsp
<%@page import="sample.mashupcenter.tidyhtml.Html2XmlUrlViewBean"%>
<%
Html2XmlUrlViewBean htViewBean = new Html2XmlUrlViewBean();
htViewBean = (Html2XmlUrlViewBean) htViewBean.getViewBeanFromRequest(request);
ResourceBundle i18n = ResourceBundle.getBundle(htViewBean.getI18NProperties(),
request.getLocale());
String objectId = htViewBean.getEntry().getObjectId();
String id = com.ibm.mashuphub.helper.PluginHelper.getClientId(
htViewBean.getPluginId(), objectId);
%>
<br/>
<label for='htmlurl'><%=i18n.getString("form.htmlurl.label") %></label>
<div class="rightCol">
<input type='text'
id='<%=id%>_htmlurl'
name='<%= Html2XmlUrlViewBean.PARAM_HTMLURL %>'
value='<%= htViewBean.getHtmlUrl() %>'
maxlength='256' style='width=600px;' />
</div>
<div class="rightCol">
<input type='checkbox'
id='<%=id%>_snapshot'
name='<%= Html2XmlUrlViewBean.PARAM_SNAPSHOT %>'
value='y'
<%= "y".equals(htViewBean.getSnapshot()) ? "verificado" : "" %> />
<%= i18n.getString("form.snapshot.label") %>
</div>
|
Se for ignorada a instrução de importação, a finalidade das duas primeiras instruções é recuperar o ViewBean associado ao JSP. É um pouco diferente da forma como os JSPs tipicamente recuperam seus Java beans associados, que é a partir do objeto do pedido. Correspondente aos elementos de entrada de formulário, há dois elementos de entrada HTML do tipo texto e uma caixa de opção, respectivamente. Observe que usamos as constantes PARAM_HTMLURL e PARAM_SNAPSHOT a partir da classe Html2XmlUrlViewBean para nomear os dois elementos de entrada. Estes nomes aparecerão como nomes na cadeia de consulta da URL enviada quando o botão Avançar é clicado. Usar as constantes da cadeia é a melhor forma de assegurar que elas correspondam exatamente ao que O servidor espera. Finalmente, inicializamos estes elementos de entrada usando o valor anterior recuperado pelo método renderEditor.
Eu mencionei anteriormente nesta seção que o método displayHtmlPage na classe Html2XMLEditorPlugin será usado para servir a próxima página do editor. O método displayHtmlPage não é herdado da classe base BaseEditorPlugin e usa dois parâmetros de tipo RequestData e Entry. Um EditorPlugin pode apresentar qualquer quantidade de métodos públicos com a mesma assinatura. Todos estes métodos podem ser chamados pelo cliente executando no navegador através de uma chamada AJAX.
Lista 6. Método displayHtmlPage
public ViewBean displayHtmlPage(RequestData rdata, Entry entry)
{
ResourceBundle i18n = ResourceBundle.getBundle(I18N_RESFILE,rdata.getLocale());
String pluginId = this.getId();
// do not use "url" since the latter got intercepted in RequestData.init();
String sHtmlUrl = rdata.getParameter( Html2XmlUrlViewBean.PARAM_HTMLURL );
String snapshot = rdata.getParameter( Html2XmlUrlViewBean.PARAM_SNAPSHOT );
log.debug("snapshot,sHtml=" + snapshot + "," + sHtmlUrl );
Html2XmlContentViewBean htViewBean = new Html2XmlContentViewBean();
htViewBean.setEntry(entry);
htViewBean.setHtmlUrl( sHtmlUrl );
htViewBean.setSnapshot( snapshot );
FormViewBean form = new FormViewBean();
form.setSuffix( htViewBean.getSuffix() );
form.addComponent( htViewBean );
form.setOnsubmit(PluginHelper.getClientMe(pluginId,
entry.getObjectId())+".submit();");
form.setEntry(entry); // must be set, used to init JS plugin object
FrameViewBean frame = new FrameViewBean();
frame.addComponent(form);
frame.setLabel(entry.getTitle());
frame.setTitle(i18n.getString("frame.tabtitle"));
frame.setEntry(entry);
frame.setHelpPath( HELPPATH );
JSONAJAXResponseViewBean ajaxViewBean = new JSONAJAXResponseViewBean();
ajaxViewBean.setMethod(JSONAJAXResponseViewBean.METHOD_SHOW_EDITOR);
ajaxViewBean.setCode( JSONAJAXResponseViewBean.PAGE_CONTENT );
ajaxViewBean.addComponent(frame);
return ajaxViewBean;
}
|
O propósito deste método é gerar uma segunda página do editor para os usuários verificarem o conteúdo do HTML recuperado. O correto é um tipo de retorno ViewBean. A lógica dentro do método displayHtmlPage é similar ao método renderEditor discutido anteriormente com três diferenças perceptíveis:
- Em vez de recuperar valores de configuração anteriormente digitados a partir da instância Entry, recuperamos o que o usuário digitou durante esta sessão de edição chamando o método getParameter do RequestData. Estes parâmetros correspondem aos elementos de entrada no formulário JSP enviado através de uma chamada AJAX para o servidor.
- Cada página exige um ViewBean diferente. Este método instancia uma instância de Html2XmlContentViewBean. Como antes, ele deve ser quebrado dentro de um cadeia FormViewBean, FrameViewBean. Além disso, precisamos quebrar ainda mais o FrameViewBean em uma instância JSONAJAXResponseViewBean. O mais recente acontecido automaticamente no método renderEditor mas precisa ser explicitamente feito aqui.
- Como forneceremos nosso próprio JavaScript, mostramos uma pequena variação no JavaScript passado no método setOnsubmit. Em vez de chamar diretamente invokeServer, chamaremos o método submitno JavaScript associado.
Um detalhe adicional importante é a chamada para a instância do criador de logs estático para registrar parâmetros específicos do usuário para ajudar na determinação de problemas.
Html2XmlContentViewBean e o JSP associado
O Html2XmlContentViewBean é muito simples e basicamente retorna apenas um caminho JSP diferente e o sufixo do Html2XmlUrlViewBean que procuramos anteriormente. O leitor pode examiná-lo através do pacote anexado e não insistiremos sobre ele. A página do editor a ser gerada também é simples, consistindo de uma área para exibir o HTML recuperado. A captura de tela a seguir mostra um canto da área de exibição:
Figura 3. Visualização da página de conteúdo HTML
Examinamos em seguida o arquivo JSP associado tidyhtmlContent.jsp. Para gerar a área de exibição, você pode ver que o JSP associado simplesmente inclui um único elemento div na parte inferior do arquivo JSP. Como usaremos o atributo do id posteriormente, este é um bom lugar para discutir sua construção.
O atributo do id deve ser exclusivo entre todos elementos HTML dentro de uma janela do navegador. Usando o id, a API fornecida pelo navegador pode recuperar os elementos HTML como objetos DOM JavaScript, permitindo a manipulação dinâmica. Como um usuário tem múltiplas instâncias de um editor de plug-ins aberta ao mesmo tempo, os elementos HTML no modelo JSP serão instanciados múltiplas vezes. Para assegurar que os IDs desses elementos sejam exclusivos, chamamos o método getClientId do PluginHelper para recuperar o ID de instância de feed exclusivo e anexá-lo ao ID.
Lista 7. tidyhtmlContent.jsp
<%@page import="sample.mashupcenter.tidyhtml.Html2XmlContentViewBean"%>
<%
Html2XmlContentViewBean htViewBean = new Html2XmlContentViewBean();
htViewBean = (Html2XmlContentViewBean) htViewBean.getViewBeanFromRequest(request);
ResourceBundle i18n = ResourceBundle.getBundle(htViewBean.getI18NProperties(),
request.getLocale());
String objectId = htViewBean.getEntry().getObjectId();
String id = com.ibm.mashuphub.helper.PluginHelper.getClientId(
htViewBean.getPluginId(), objectId);
String me = com.ibm.mashuphub.helper.PluginHelper.getClientMe(
htViewBean.getPluginId(), objectId);
String snapshot = "\"" + htViewBean.getSnapshot() + "\"";
String htmlUrl = htViewBean.getHtmlUrl();
htmlUrl = ( htmlUrl == null ? "\"\"" : "\"" + htmlUrl + "\"" );
%>
<script type="text/javascript">
dojo.registerModulePath("plugins.tidyhtml" ,
"../../../../client/plugins/sample.mashupcenter.tidyhtml/script");
dojo.require("plugins.tidyhtml.PreviewHtml");
new plugins.tidyhtml.PreviewHtml(
<%= me %>.plugin_id,
<%= me %>.entry_id,
<%= me %>.workflow);
<%=me%>.init( <%= htmlUrl %> , <%= snapshot %> );
<%=me%>.onLoadEditor();
</script>
<div id='<%=id%>_htmlContent' style='width:100%;
overflow:auto; border: 2px solid #000000;'>
</div>
|
Um novo aspecto deste JSP é a inclusão de JavaScript customizado a ser executado no lado do cliente. A estrutura de geração de feeds do IBM Mashup Center usa o pacote Dojo AJAX. Consulte a seção Recursos para o link para a documentação do Dojo. Estaremos usando o pacote Dojo AJAX em nosso JavaScript customizado. A maior parte do JavaScript customizado reside em uma classe Dojo chamada "plugins.tidyhtml.PreviewHtml".
Para usá-lo, precisamos importá-lo usando uma chamada de função dojo.require. A chamada de função registerModulePath do Dojo é usada para dizer ao Dojo como localizar as classes a partir do "módulo" plugins.tidyhtml. Observe que o caminho especificado seja relativo ao caminho onde o pacote Dojo está localizado e, dessa forma, exige a referência de retrocesso "../../../..". A lógica de inicialização acima é gerada de forma sequencial dentro de uma tag de script. Além disso, o JavaScript sequencial cria uma instância da classe PreviewHtml e chama seus métodos init e onLoadEditor. A próxima seção examina em muitos detalhes da classe PreviewHtml.
A classe Dojo PreviewHtml herda da classe hub.managers.InvokePlugin que é parte da estrutura de geração de feeds do lado do cliente. A classe InvokePlugin é descrita ainda mais na seção 6.3.2 da Referência da Interface de Programação de Aplicativos, Versão 1.0. Os métodos de importância na classe Dojo PreviewHtml são onLoadEditor e populateContent.
Lista 8. Classe Dojo PreviewHtml
onLoadEditor: function()
{
this.id = this.getEditorId();
this.htmlContentNode = dojo.byId( this.id + '_htmlContent' );
this.populateContent();
},
populateContent: function( )
{
console.log( "populateContent chamado" );
var baseUrl = hub.urls.getAjaxUrl( this.plugin_id,this.entry_id, 'getHtmlContent');
var htmlurl = baseUrl + "?htmlurl=" + escape( this.htmlUrl );
if ( this.htmlContentInternalNode )
this.htmlContentNode.removeChild( this.htmlContentInternalNode );
this.htmlContentInternalNode = document.createElement( 'iframe' );
this.htmlContentInternalNode.setAttribute( "src", htmlurl );
this.htmlContentInternalNode.setAttribute( "width", "100%" );
this.htmlContentInternalNode.setAttribute( "height", "400px" );
this.htmlContentNode.appendChild( this.htmlContentInternalNode );
},
|
A função populateContent é chamada de onLoadEditor durante o tempo de carregamento da página. Ela dinamicamente cria um iframe para exibir o HTML recuperado inicializando o efeito de todas as folhas de estilo incluídas e scripts evitando que eles afetem a aparência de outras páginas. O iframe dinamicamente criado é anexado ao div estático criado pelo JSP. Para recuperar o nó DOM correspondente à área de exibição, usamos o ID exclusivo do elemento div gerado pela anexação do ID de instância de feed exclusivo a um sufixo comum.
No lado do servidor, usamos um método na classe PluginHelper para obter o ID de instância de feed exclusivo. No lado do navegador, chamamos a função getEditorId do pai da classe Dojo PreviewHtml como, por exemplo, hub.managers.InvokePlugin. Para recuperar o conteúdo HTML, iremos tirar vantagem do atributo "src" do Iframe. O iframe será automaticamente recuperado e exibe o conteúdo apontado pelo atributo src durante a inicialização. Configuraremos o atributo src para chamar o método getHtmlContent do plug-in do editor. Observe a forma como criamos a URL chamando a função getAjaxUrl e anexando o resultado para a cadeia "getHtmlContent".
Método AJAX para recuperar HTML
Eu mencionei em uma seção anterior que todos os métodos públicos com RequestData e Entry como parâmetros podem ser chamados usando uma chamada AJAX. Em particular, o método getHtmlContent pode ser chamado pela classe Dojo PreviewHtml para retornar o HTML da URL fornecida pelo usuário. Como a recuperação de HTML real é comum para a geração de feeds e será abordada posteriormente, eu não fornecerei nenhum fragmento de código aqui. A única coisa que eu quero apontar é o tipo de retorno do método. No exemplo anterior, o método AJAX displayHtmlPage retorna um ViewBean. Os métodos AJAX em geral podem retornar qualquer objeto e seu valor toString será retornado. Consulte a seção 6.3.2 de Referência da Interface de Programação de Aplicativos, Versão 1.0.
Nosso último método do editor: saveFeedEntry
saveFeedEntry é outro método público de Html2XmlEditorPlugin chamado através do AJAX para manipular a etapa final no processo de edição, salvando o que o usuário digitou. Ele é simular aos métodos save em outros plug-ins. O que há de novo na manipulação de "recursos". Os recursos diferem de atributos em tamanho e tipo. Os recursos podem ser binários e podem ter até um gigabyte de tamanho. Em contraste, os atributos são limitados a cadeias de tamanho 10 MB. O tamanho limite para o atributo deve ser suficiente para o conteúdo, mas para fins ilustrativos, salvaremos o conteúdo HTML como um recurso. Quando a opção de captura instantânea está marcada, o gerador somente irá recuperar o conteúdo HTML a partir da URL especificada uma vez. O conteúdo HTML é então convertido para XML e salvo. Todos os pedidos de geração de feeds subsequentes serão satisfeitos a partir do XML salvo. Para tratar o caso em que o usuário desejar fazer outra captura instantânea porque o site pode ter mudado, gostaríamos de excluir a cópia salva sempre que o feed for editado. O fragmento de código mostra como isto é feito em um processo de duas etapas: recupere o recurso por nome, seguido pela chamada do método deleteResource no objeto retornado.
Lista 9. Método saveFeedEntry
try {
entry.generateURL(rdata.getBaseUrl(), this.getId() );
entry.addAttribute(Html2XmlUrlViewBean.PARAM_HTMLURL, sHtmlUrl , this.getId() );
entry.addAttribute(Html2XmlUrlViewBean.PARAM_SNAPSHOT , snapshot , this.getId() );
// depois de cada edição, limpe todas as capturas instantâneas armazenadas em cache
Resource oldRes = entry.getResource( Html2XmlConstants.CACHED_XHTML );
if ( oldRes != null )
oldRes.deleteResource();
} catch (HubException ex) {
log.error("Erro incluindo atributo de entrada.",ex);
}
|
Finalmente concluímos com o Editor e no Gerador.
A classe Html2XmlGeneratorPlugin estende o BaseGeneratorPlugin e deve implementar o método abstrato generateFeed. Não deveria ser surpresa que os parâmetros de entrada de tipo RequestData e Entry são idênticos ao que está sendo passado nos métodos EditorPlugin chamados pela estrutura de geração de feeds. Para gerar o feed, alguém deve primeiro recuperar os atributos contendo as informações de configuração salvas durante o processo de edição. Isto é feito através da chamada do método getAttribute a partir de Entry.
Lista 10. Método generateFeed
public FeedContent generateFeed(RequestData rdata, Entry entry) {
String sHtmlUrl = entry.getAttribute(Html2XmlUrlViewBean.PARAM_HTMLURL );
String snapshot = entry.getAttribute(Html2XmlUrlViewBean.PARAM_SNAPSHOT );
|
Como este plug-in não suporta a parametrização, não precisamos recuperar os parâmetros fornecidos pelo tempo de execução. Nós retornaremos o conteúdo XML salvo ou recuperaremos o conteúdo HTML e converteremos para XML usando JTidy. A lógica ilustra como os recursos são criados e é muito direta.
Lista 11. Corpo do generateFeed
String result = "O HTML pode ter mudado. Tabela não localizada.";
Resource oldRes = entry.getResource( Html2XmlConstants.CACHED_XHTML );
if ( "y".equals( snapshot ) && oldRes != null ) {
log.warn( "retornando armazenado em cache, captura instantânea=" + snapshot );
return new FeedContent(oldRes.loadResource(), entry.getLifeTime());
}
String sHtml = getXhtml( sHtmlUrl );
if ( sHtml.length() > 0 ) {
result = sHtml;
if ( "y".equals( snapshot ) ) {
try {
Resource prepared = new Resource();
prepared.setObjectid( entry.getObjectId() );
prepared.setMimetype( "text/xml; charset=utf-8" );
prepared.setFilename( Html2XmlConstants.CACHED_XHTML );
prepared.uploadResource( sHtml.getBytes( "utf-8" ) );
} catch (HubException e) {
log.error(e);
}
}
}
return new FeedContent( result.getBytes( "utf-8" ), entry.getLifeTime());
|
Detalhes adicionais sobre como a entrada HTML que é convertida em XML pode ser localizada nos arquivos de origem Java. Eu apenas mencionarei dois pontos principais. Para tornar a saída XML utilizável pelo editor mashup de feeds, excluímos todas as declarações DOCTYPE. Além disso, a lógica de geração faz a suposição simplificada de que a entrada HTML está em UTF-8 e precisa ser melhorada para suportar outras linguagens.
O projeto Eclipse completo com todos os arquivos de origem está disponível como um arquivo zip na área de download. Além disso, para facilitar tentar o plug-in, o arquivo zip do plug-in (sample.mashupcenter.tidyhtml.zip) também é fornecido. Para instalar o plug-in, execute as seguintes etapas:
- Faça download do Tidy.jar a partir do link na seção de recursos.
- Depois da remoção dos arquivos de classe do pacote org.w3c.dom, inclua o Tidy.jar no arquivo zip do plug-in no diretório WEB-INF/lib.
- Coloque o arquivo zip do plug-in no diretório <WebApplication>/WEB-INF/plugins.
- Pare e reinicie o servidor.
Já abordamos a construção de um plug-in mais complicado envolvendo múltiplas páginas do editor, JavaScript customizado e salvando os recursos. Você agora tem o básico para começar a estender as capacidades de geração de feeds do IBM Mashup Center. Um artigo subsequente discutirá tópicos mais avançados como segurança e parametrização.
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Samples for this article | Download.zip | 325KB | HTTP |
Informações sobre métodos de download
Aprender
-
Para aprender os fundamentos da criação de um plug-in do IBM Mashup Center, leia "
Estenda a abrangência de dados para IBM Mashup Center"(developerWorks, de agosto de 2008).
-
Seção 6 de Referência da Interface de Programação de Aplicativos, Versão 1.0 é a documentação oficial para a API do plug-in do IBM Mashup Center.
-
Aprenda sobre o DOM (Document Object Model) da W3C.
-
Para aprender sobre o Dojo, leia The Book of Dojo.
-
Para obter exemplos sobre como usar o HTML convertido, leia "
Converter de HTML para XML com HTML Tidy(developerWorks, de setembro de 2003).
- Na
área de Gerenciamento de Informações no developerWorks,
obtenha os recursos que precisa para avançar suas qualificações nos produtos IBM Information Management.
- Navegue na
livraria de tecnologia
para os manuais sobre estes e outros tópicos técnicos.
Obter produtos e tecnologias
-
Você pode fazer o download de JTidy from SourceForge.
-
Para obter experiência prática com IBM Mashup Center, visite Lotus greenhouse.
-
Faça o download uma versão de teste gratuita do IBM Mashup Center
da developerWorks.
-
Você também pode acessar Mashup Center na Amazon Elastic Compute Cloud.
- Faça o download
de versões de avaliação do produto IBM
ou explore
as versões de teste no IBM SOA Sandbox e coloque as mãos nas ferramenta de desenvolvimento de aplicativos e produto de middleware DB2®, Lotus®, Rational®, Tivoli® e WebSphere®.
Discutir
- Participar do fórum de discussão.
- Confira
Blogs do developerWorks e
envolva-se na
comunidade do developerWorks.
Louis Mau is part of the InfoSphere MashupHub development team. His current focus is to help customers build situational applications using the IBM Mashup Center. Prior to this role, he was the architect for DB2 Everyplace Sync Server, which helps synchronize data from enterprise databases onto a small foot print database running on mobile devices.