WebSphere Portal Theme: Access page metadata - websphere

I am trying to fetch the page metadata using JSP file. I am using below code to fetch the page metadata.
<%!
public void testMeta(PageContext pageContext, String nodeId) {
Map<String, Object> parentMeta = (Map<String, Object>)pageContext.getAttribute(nodeId, PageContext.REQUEST_SCOPE);
//System.out.println("Meta Object " + nodeId + ": " + parentMeta);
Set<Map.Entry<String, Object>> entry1 = parentMeta.entrySet();
//System.out.println("No. of elements: " + entry1.size());
for (Map.Entry<String, Object> entry: entry1 ) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
Set<String> keySet = parentMeta.keySet();
if (keySet != null ){
System.out.println("Keyset contains something");
} else {
//System.out.println("Keyset is NULL");
}
}
%>
<c:if test="${empty parentID}">
<c:set var="parentID" value="${param.parentID}" />
</c:if>
<c:set var="showHidden" value="${param.showHidden}" />
<c:set var="parentNode" value="${wp.navigationModel[parentID]}"/>
<c:if test="${curLevel==1}">
<c:set var="dirMeta" value="${parentNode.metadata}" scope="request" />
{
"ishidden":"parentNode.metadata['com.ibm.portal.Hidden']" //this is working
"attributes": {
<% testMeta(pageContext, "dirMeta"); %>
}
}
</c:if>
In above code, I am passing page identifier from client side fetch the metadata of the page and its children. I am getting object of NavigationNodeBean using wp.navigationModel bean.
I am always getting empty Map in the testMeta method, the size of entry1 set is always 0 though there are number of metadata entries present on the page.
Does any one have faced this kind of issue?
Note:
I cannot use as I am not using the portal's rendering, I am using portal theme with angular, which gets the page content as and when necessary. I am using angular's router to decide which page to render, and in this case portal doesn't have any of the state information about the page I am rendering.

Related

How get value of tag <p:menu> in primefaces

I am doing a web aplication where I have a menu with a list entities and this entities will be evaluated all it is in a facelets template and I now I need to get the ID of this entity to can evaluate How it do ?
I thought it:
<p:menu model="#{entidadView.menuModel}" toggleable="true" >
<p:ajax listener="#{grupoView.storeEntidad}"/>
</p:menu>
and My bean it is:
public MenuModel getMenuModel(){
DefaultSubMenu subMenu2 = new DefaultSubMenu("Auditoria");
for (Entidad entidad : getAllEntidad() ){
item = new DefaultMenuItem(entidad.getNombre());
item.setOutcome("/auditar.xhtml");
subMenu2.addElement(item);
}
model.addElement(subMenu2);
//Event to Ajax
public void storeEntidad(ValueChangeEvent evento){
this.idEntidad = evento.getNewValue().toString();;
System.out.println(idEntidad);
}
but say me this error:
<p:ajax> Unable to attach behavior to non-ClientBehaviorHolder parent
I did it only send the parameter by the URL of my web pages and I capture it then.
My bean:
public MenuModel getMenuModel(){
DefaultSubMenu subMenu2 = new DefaultSubMenu("Auditoria");
for (Entidad entidad : getAllEntidad() ){
idEntidad = String.valueOf(entidad.getEntidad_id());
item = new DefaultMenuItem(entidad.getNombre());
item.setParam("entidad", idEntidad);
item.setOutcome("/auditar.xhtml");
subMenu2.addElement(item);
}
model.addElement(subMenu2);
}
And the next Pages I capture so:
<html ...>
<f:metadata>
<f:viewParam name="entidad" value="#{grupoView.idEntidad}"/>
</f:metadata>
<body>
And finaally It was okay !!! (Y)

JSF file download exception handling (how to prevent view rerendering)

Good day, friends!
First of all, I'm sorry for my English. Here is my question:
I'm new to JSF (2.0), and I'm trying to use BalusC algorythm for file download from managed bean. Function works correctly and "Save As..." dialog appears in browser. But I don't know how to return file download error message (exception, DB error etc. in backing bean method) without view reload/redirect.
My hidden button on the view:
<h:form id="detailsDecisionMainForm">
<h:inputHidden id="docId" value="" />
<h:commandButton id="downloadAction" action="#{detailsDecisionGridBean.downloadForm()}" style="display: none;" />
</h:form>
My managed bean (which scope can I use? I've tried request and view scopes) method:
public String downloadForm() {
log.fine("downloadForm call");
PdfService pdfService = new PdfServiceImpl();
ArmCommonService armCommonService = new ArmCommonServiceImpl();
String errorMessage = null;
try {
Long opUni = new Long(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("detailsDecisionMainForm:docId"));
log.fine("Document opUni = " + opUni);
DocXML docXML = armCommonService.getDocXMLById(opUni);
if (docXML != null) {
File pdfFile = pdfService.getPdfReport(docXML.getXml(), docXML.getType());
if (pdfFile != null) {
DownloadUtils.exportPdf(pdfFile);
} else {
log.log(Level.SEVERE, "downloadForm error: pdf generation error");
errorMessage = "PDF-document generation error.";
}
} else {
log.log(Level.SEVERE, "downloadForm error: xml not found");
errorMessage = "XML-document not found.";
}
} catch (Exception ex) {
log.log(Level.SEVERE, "downloadForm exception: " + ex.getMessage());
errorMessage = "File download exception.";
}
if (errorMessage != null) {
FacesContext.getCurrentInstance().addMessage("detailsDecisionMainForm:downloadAction", new FacesMessage(errorMessage));
}
return null;
}
DownloadUtils.exportPdf() procedure works correctly:
public static void exportPdf(File file) throws IOException {
InputStream fileIS = null;
try {
log.fine("exportPdf call");
fileIS = new FileInputStream(file);
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType(APPLICATION_PDF_UTF_8);
byte[] buffer = ByteStreams.toByteArray(fileIS);
ec.setResponseContentLength(buffer.length);
ec.setResponseHeader(HttpHeaders.CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_VALUE, new String(file.getName().getBytes(StandardCharsets.UTF_8))));
ec.getResponseOutputStream().write(buffer);
fc.responseComplete();
} catch (Exception ex) {
log.log(Level.SEVERE, "exportPdf exception: " + ex.getMessage());
} finally {
if (fileIS != null) {
fileIS.close();
log.fine("exportPdf inputstream file closed");
}
}
}
What can I do to prevent view rerendering after downloadForm() error/exception? And how can I show javascript alert() with message text (in future - jQuery.messager panel with error text)?
Thank you!
In order to prevent a full page reload, you have to submit form by ajax. But, in order to be able to download a file, you have to turn off ajax. This doesn't go well together.
Your best bet is to split the action in two requests. First send an ajax request which creates the file on a temporary location in the server side. When this fails, you can just display a faces message the usual way. When this succeeds, you can just automatically trigger the second request by submitting a hidden non-ajax command button via conditionally rendered JavaScript. This second request can then just stream the already successfully created file from the temporary location to the response.
A similar question was already asked and answered before: Conditionally provide either file download or show export validation error message. But this involves PrimeFaces and OmniFaces. Below is the standard JSF approach:
<h:form id="form">
...
<h:commandButton value="Export" action="#{bean.export}">
<f:ajax ... render="result" />
</h:commandButton>
<h:panelGroup id="result">
<h:messages />
<h:commandButton id="download" action="#{bean.download}"
style="display:none" />
<h:outputScript rendered="#{not facesContext.validationFailed}">
document.getElementById("form:download").onclick();
</h:outputScript>
</h:panelGroup>
</h:form>
And use this #ViewScoped bean (logic is based on your existing logic). Basically, just get hold of the File as instance variable during export action (ajax) and then stream it during download action (non-ajax).
private File pdfFile;
public void export() {
try {
pdfFile = pdfService.getPdfReport(...);
} catch (Exception e) {
context.addMessage(...);
}
}
public void download() throws IOException {
DownloadUtils.exportPdf(pdfFile);
}
See also:
How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
Store PDF for a limited time on app server and make it available for download

primefaces 4.0 p:graphicImage firefox bug

Here is my problem with firefox using primefaces 4.0 communication version: p:graphicImage
I have a list of model, whenever I click 1 item, I would like to get 1 image respectively
In xhtml file
<p:fieldset id="modelDiagramView" style="width:100%;height:1280px">
<p:panel id="panel">
<p:graphicImage value="#{modelBean.modelImage}" style="width: 100%;" cache="false"/>
</p:panel>
</p:fieldset>
in java bean, only session scope and application scope are running well
public StreamedContent getModelImage() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
System.out.println("render_response: id=" + modelID);
// So, we're rendering the HTML. Return a stub StreamedContent so
// that it will generate right URL.
// modelImage = new DefaultStreamedContent();
if (modelID != null)
getModelImage(modelID);
} else {
System.out.println("real reander: id=" + modelID);
if (modelID != null)
getModelImage(modelID);
}
return modelImage;
}
In chrome, when I click to item in list, the p:graphicImage will render a new image, however in firefox, only the first item's image will be render, if I want to display the next clicked item, I have to refresh browser(F5). Is it primefaces bug, how can I prevent that problem? Please help me
It's just a "bug" that browsers doesn't refresh a image with ajax if the URL will not be changed. Therefore you should add a random number to the resource url as below example.
xhtml
<p:graphicImage value="#{bean.stream}" id="pic" width="200">
<f:param name="randomNumber" value="#{beanxxx.randomNumber}"/>
</p:graphicImage>
beanxxx
public String getRandomNumber() {
Random r = new Random();
int low = 10;
int high = 100;
int result = r.nextInt(high-low) + low;
return Integer.toString(result);
}

Spring form elements, multiple nestedPath and referencing inputs with Javascript

I have complex form objects, with unlimited depth and I'm trying to edit them on jsp with spring form tags.
Main modelAttribute is bind to spring form, and while I'm iterating through childs, I use nestedPath and everithing works OK. As result I have generated input names something like:
name="elements['secondColumn'][0].elements[0].removed"
Problem is that I can not know the generated name. Why I need it? Let's say that I have delete button from which I want to set appropriate field "removed" to 1.
Update:
How does it works? I am using tag files which are recursively calling them self.
container.tag
<c:forEach items="${elements}" var="element" varStatus="index">
<spring:nestedPath path="elements[${index.count - 1}]">
<my:elementConfig element="${element}">
<my:container elements="${element.elements}"/>
</my:elementConfig>
</spring:nestedPath>
</c:forEach>
elementConfig.tag
...
<form:hidden path="removed"/>
...
<button onclick="delete('howToGetNameOfRemovedHidden')">Delete</button>
...
<jsp:doBody/>
...
Closest match I allready found is a "nestedPath" pageContext attribute, but it contains the name of the modelAttribute (form) name too.
Is there official way to get the generated name?
Thanks
I guess you could go through additional attributes, using for example the HTML5 data-* one:
<c:set var="i" value="0" />
<c:foreach [...]>
<form:input path="[...].remove" data-inputid="input${i}" />
<button class="removebutton" data-inputid="input${i}">Remove</button>
<c:set var="i" value="${i + 1}" />
</c:foreach>
Then, using jQuery for example:
$(function() {
$(".removebutton").click(function() {
var dataInputId = $(this).data("inputid");
$("input[data-inputid='" + dataInputId + "']").val(1);
});
});
But don't forget: if you have nested loops, the data-input should there be unique through the whole document.
As it seems there is no official support for getting generated input names, so I've made a function which handles it. It is based on a functionality I found in Spring form tag library.
Static methods:
public class JspUtils {
public static String escapeJS( String value) {
return StringEscapeUtils.escapeJavaScript( value);
}
public static String getPath( PageContext pageContext, String name) {
String path = (String)pageContext.getRequest().getAttribute( "nestedPath");
if (path == null)
path = (String)pageContext.getAttribute( "nestedPath");
if (path == null)
return name;
path = path.substring( path.indexOf( ".") + 1);
path += name;
return path;
}
public static String getPathJsEscaped( PageContext pageContext, String name) {
return StringEscapeUtils.escapeJavaScript( getPath(pageContext, name));
}
}
tld definition:
<function>
<description>
Get nested path value as string
</description>
<name>getPath</name>
<function-class>com.pathfix.JspUtils</function-class>
<function-signature>java.lang.String getPath(javax.servlet.jsp.PageContext, java.lang.String)</function-signature>
</function>
<function>
<description>
Get nested path value as javascript escaped string
</description>
<name>getPathJsEscaped</name>
<function-class>com.pathfix.JspUtils</function-class>
<function-signature>java.lang.String getPathJsEscaped(javax.servlet.jsp.PageContext, java.lang.String)</function-signature>
</function>
Example usage:
<%# taglib prefix="pathfix" uri="http://pathfix.com"%>
Name: <form:input path="name"/>
Test it!

How to use p:graphicImage with StreamedContent within p:dataTable? [duplicate]

This question already has answers here:
Display dynamic image from database or remote source with p:graphicImage and StreamedContent
(4 answers)
Closed 7 years ago.
I want to dynamically load images from a database withing a PrimeFaces data table. Code looks like as follows which is based on this PF forum topic:
<p:dataTable id="tablaInventario" var="inv" value="#{registrarPedidoController.inventarioList}" paginator="true" rows="10"
selection="#{registrarPedidoController.inventarioSelected}" selectionMode="single"
update="tablaInventario tablaDetalle total totalDesc" dblClickSelect="false" paginatorPosition="bottom">
<p:column sortBy="producto.codigo" filterBy="producto.codigo">
<f:facet name="header">#{msg.codigo}</f:facet>
#{inv.producto.codProducto}
</p:column>
<p:column>
<f:facet name="header">Foto</f:facet>
<p:graphicImage id="photo" value="#{registrarPedidoController.streamedImageById}" cache="FALSE">
<f:param name="inv" value="#{inv.id}" />
</p:graphicImage>
</p:column>
</p:dataTable>
with
public StreamedContent getStreamedImageById() {
DefaultStreamedContent image = null;
String get = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("inv");
System.out.println("[Param]: " + get); // This prints null.
Long id = new Long(get);
List<Inventario> listInventarios = controladorRegistrarPedido.listInventarios();
for (Inventario i : listInventarios) {
if (i.getId().compareTo(id) == 0) {
byte[] foto = i.getProducto().getFoto();
image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
}
}
return image;
}
However I can't get it work. My param is passing "null" to my backing bean. How is this caused and how can I solve it?
I am using Netbeans 6.9.1, JSF 2.0 and Primefaces 2.2.RC2.
I went on using BalusC first solution, it worked fine but images aren't being rendered in the UI. Exceptions Glassfish is throwing up:
WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
at com.sun.faces.mgbean.BeanManager$ScopeManager$ViewScopeHandler.isInScope(BeanManager.java:552)
Well seems I get working thanks to BalusC. I've to used RequestScoped, SessionScoped or ApplicationScoped for managing the getStreamedImageId. However in the UI is always setting the default image (for the null cases) and not as expected the image that correspondes to each row. The new code is:
public StreamedContent streamedById(Long id) {
DefaultStreamedContent image = null;
System.out.println("[ID inventario]: " + id);
List<Inventario> listInventarios = controladorRegistrarPedido.listInventarios();
for (Inventario i : listInventarios) {
if (i.getId().equals(id)) {
byte[] foto = i.getProducto().getFoto();
if (foto != null) {
System.out.println(" [Foto]: " + foto);
image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
break;
}
}
}
if (image == null) {
System.out.println(" [Image null]");
byte[] foto = listInventarios.get(0).getProducto().getFoto();
image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
}
System.out.println(" [Foto Streamed]: " + image);
return image;
}
The <p:graphicImage> will call the getter method twice. First time is when the <img> element is to be rendered to HTML and thus requires an URL in the src attribute. If you just return new DefaultStreamedContent(), then it will autogenerate the right URL in src attribute. Second time is when the browser really requests the image, this is the moment when you should return the actual image.
So, the getter method should basically look like this:
public StreamedContent getStreamedImageById() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
// So, browser is requesting the image. Get ID value from actual request param.
String id = context.getExternalContext().getRequestParameterMap().get("id");
Image image = service.find(Long.valueOf(id));
return new DefaultStreamedContent(new ByteArrayInputStream(image.getBytes()));
}
}
images are saved in the database as byte[] if we save them through hibernate. I uploaded the images with <p:fileUpload... tag then I save the image alongwith other data values using hibernate.
On second page, I'm displaying the whole table data (of course with images) using
<p:dataTable var="data" value="#{three.all}" ....
and dynamic Images using
<p:graphicImage alt="image" value="#{three.getImage(data)}" cache="false" >
<f:param id="image_id" name="image_id" value="#{data.number}" />
</p:graphicImage></p:dataTable>
Here "three" is the name of Backing Bean. In method getAll(), I'm retrieving data from table through hibernate and in the same method, I've created a HashMap<Integer, byte[]>. HashMap is an instance variable of the bean and The Bean is SessionScoped. I'm putting the images (which are in byte[] form) alongwith an integer image_id.
code:
for (int i=0; i<utlst.size(); i++ ){
images.put(utlst.get(i).getNumber(), utlst.get(i).getImage());}
//utlst is the object retrieved from database. number is user-id.
In the view getImage.xhtml, <p:graphicImage alt="image" value="#{three.getImage(data)}" cache="false" > it calls the method getImage(data /*I am passing current object of the list which is being iterated by*/ )
code of getImage:
public StreamedContent getImage(Util ut) throws IOException {
//Util is the pojo
String image_id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("image_id");
System.out.println("image_id: " + image_id);
if (image_id == null) {
defaultImage=new DefaultStreamedContent(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/Capture.PNG"), "image/png");
return defaultImage;
}
image= new DefaultStreamedContent(new ByteArrayInputStream(images.get(Integer.valueOf(image_id))), "image/png");
return image;
}
just keep your dynamic Images with ids in A HashMap in the session then they will be correctly streamed.
Thanks & regards,
Zeeshan
In PrimeFaces 3.2 the bug is still present. I do the workaround with
<p:graphicImage value="#{company.charting}">
<f:param id="a" name="a" value="#{cc.attrs.a}" />
<f:param id="b" name="b" value="#{cc.attrs.b}" />
</p:graphicImage>
and
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String a= externalContext.getRequestParameterMap().get("a");
String b= externalContext.getRequestParameterMap().get("b");
But even with this the bean is called 2 times. But in the second call variable a + b is filled ;-)
Damn bug

Resources