Rendering out a page from an OSGI Bundle | Adobe Higher Education
Skip to main content
glenn_penridge
October 16, 2015
Risolto

Rendering out a page from an OSGI Bundle

  • October 16, 2015
  • 8 risposte
  • 1324 visualizzazioni

Hi,

I've run into an issue while trying to create a custom OSGI bundle that solves the following problem:

We have a list of several thousand keys in a CSV file that need to point to specific pages, and then render the content of that page.

Conceptually, I believe I understand how I'm supposed to do it:

  1. The OSGI bundle runs in the background, available for a *.JSP to reference.
  2. The bundle loads the CSV*, parsing the key->value from the JSP that was referenced. (eg. 54, /path/to/the/requested/resource)
  3. The bundle then renders the resource out as part of the request.

* I know the second step needs refinement (it should be loaded after the server loads, and remain in memory until it's shut down; we don't want to thrash the HDD and memory is much faster but for now this is mainly for a proof of concept.)

I should add that I'm pretty lousy when it comes to Java programming but using various tutorials I've managed to return a string so far. From that I've then tried to resolve the resource inside of the Implementation class for the bundle.

Code as follows (var names changed):

ExampleService.java:

package com.adobe.cq; public interface ExampleService { public void csvLocation(String val); public void setKey(String val); public void main(); }

ExampleServiceImpl.java:

package com.adobe.cq; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; // Required Felix files import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; // Required Sling Files import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ResourceResolverFactory; import org.apache.sling.api.resource.LoginException; // Required CQ Files import com.day.cq.wcm.api.Page; import com.day.cq.wcm.api.PageManager; // @Component // @Service public class ExampleServiceImpl implements ExampleService { private String csvLocation = "C:\\AdobeCQ\\LargeEntry.csv"; private String key = "0"; private ResourceResolverFactory resolverFactory; public void setKey(String val) { this.key = val; } public void csvLocation(String val) { this.csvLocation = val; } public void main() { BufferedReader br = null; String pageUrl = null; // // This part loads the CSV file // try { String sCurrentLine; br = new BufferedReader(new FileReader(csvLocation)); while ((sCurrentLine = br.readLine()) != null) { String[] split = sCurrentLine.split(","); if (split[0].equals(key)) { pageUrl = (split[1]).toString(); } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) { br.close(); } } catch (IOException ex) { ex.printStackTrace(); } } // // Page load request // try { ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null); PageManager pageManager = resourceResolver.adaptTo(PageManager.class); // perform actions here Page page = pageManager.getPage(pageUrl); // Right here: // This is where the issue exists-- // what would you do here to render the // contents of a retrieved page out to // the browser? resourceResolver.close(); } catch (LoginException e) { e.printStackTrace(); } } }

Please, please help me here. I've been tearing my hair out trying to figure out how to output a rendered page after retrieving a resource. What am I missing? What am I doing wrong here?

Thanks for any assistance.

Questo argomento è stato chiuso alle risposte.
Migliore risposta di smacdonald2008

Instead of returning the values in a String - why not JSON or XML:

ie - XML

<keyvalues>

<keyvalue>

  <key>keyname1</key.>

   <value>keyval</value>

 </keyvalue>

<keyvalue>

  <key>keyname2</key.>

   <value>keyval</value>

 </keyvalue>

</keyvalues>

This would make it much easier to pass back from the OSGi service and then also much easier to parse on front end component using JQuery.

8 risposte

Lokesh_Shivalingaiah
Level 10
October 16, 2015

I believe, the pages are already created with templates. You can have a placeholder in the content with a component to hold these key value pair.

with in the JSP, you can call your service class which returns the value or the content required for the component in the JSP which takes care of rendering it.

smacdonald2008
Level 10
October 16, 2015

Instead of returning the values in a String - why not JSON or XML:

ie - XML

<keyvalues>

<keyvalue>

  <key>keyname1</key.>

   <value>keyval</value>

 </keyvalue>

<keyvalue>

  <key>keyname2</key.>

   <value>keyval</value>

 </keyvalue>

</keyvalues>

This would make it much easier to pass back from the OSGi service and then also much easier to parse on front end component using JQuery.

smacdonald2008
Level 10
October 16, 2015

Also - to learn how to dynamically create XML and return it as part of an AEM custom service and how to parse it on the front end - see this AEM community article:

https://helpx.adobe.com/experience-manager/using/querying-experience-manager-data-using1.html

smacdonald2008
Level 10
October 16, 2015

Likewise - here is an article that shows how to return JSON from the AEM service and parse it on the front end:

https://helpx.adobe.com/experience-manager/using/restful-services.html

That is one of the powerful things about AEM - building back end services that return data to meet your needs (ie - xml/json) and front end components that can parse and use the data. 

Feike_Visser1
Adobe Employee
Adobe Employee
October 16, 2015

I think you are mixing the 'Page' and output here.

If you want to spool content to the response, best way is to create a servlet and then push the content with response.getWriter().

The Page-api points to an existing 'content-page' already in CRX.

If you want you can create new pages via the PageManager-api.

BTW: In you sample code you should always close the resourceResolver in the finally block, and even more try to avoid the use of admin-sessions.

glenn_penridge
October 16, 2015

By the way Simon, are you the same gentleman who runs the Phonegap blog? If so, it was terrific stuff-- helped me out with a lot of smaller apps that I was making a while back. Thanks. I'd like to add at this point that I could implement the XML and JSON services, but the amount of time and effort involved would simply not be worth it (at this point in time.) :)

So I've been trying all day to get this thing to return even basic stuff, like a page title. All I keep on getting are Server 500 errors and I'm at my wit's end now.

Here's the stack trace:

09.03.2015 17:04:58.740 *ERROR* [0:0:0:0:0:0:0:1 [1425884698419] GET /content/KeyTemplate.html HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Uncaught SlingException java.lang.NullPointerException: null at com.adobe.cq.DoubleclickServiceImpl.getTitle(ExampleServiceImpl.java:95)

Here's an example of the key-value pair that I'm using:

0,content/geometrixx/en/services
1,content/geometrixx
2.content/geometrixx/en

 

... and I've got some updated code here. Have I missed anything here? I simply can't get this thing working, no matter what I do. I've tried the documentation on the Sling site (http://sling.apache.org/documentation/tutorials-how-tos/getting-resources-and-properties-in-sling.html) as well, and I'm still getting no joy.

package com.adobe.cq; public interface ExampleService { public void csvLocation(String val); public void setKey(String val); public void main(); public String getString(); public String getTitle(); }

... and the Implementation:

package com.adobe.cq; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; // Required Felix files import org.apache.felix.scr.annotations.Service; import org.apache.felix.scr.annotations.Component; // Required Sling files import org.apache.sling.api.resource.LoginException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ResourceResolverFactory; // Required CQ Files import com.day.cq.wcm.api.Page; // @Component @Service public class ExampleServiceImpl implements ExampleService { private ResourceResolverFactory resolverFactory; private LoginException loginException; private String csvLocation = "C:\\AdobeCQ\\LargeEntry.csv"; private String key = "0"; private String pageUrl = null; public void setKey(String val) { this.key = val; } public void csvLocation(String val) { this.csvLocation = val; } public String getString() { return this.pageUrl; } private void getCSV() { BufferedReader br = null; // // This part loads the CSV file // try { String sCurrentLine; br = new BufferedReader(new FileReader(csvLocation)); while ((sCurrentLine = br.readLine()) != null) { String[] split = sCurrentLine.split(","); if (split[0].equals(key)) { pageUrl = (split[1]).toString(); } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) { br.close(); } } catch (IOException ex) { ex.printStackTrace(); } } } public void main() { this.getCSV(); } public String getTitle() { String x = null; try { ResourceResolver resourceResolver = resolverFactory.getResourceResolver(null); Resource res = resourceResolver.getResource(pageUrl); Page getPage = res.adaptTo(Page.class); x = getPage.getTitle(); resourceResolver.close(); } catch (LoginException e) { e.printStackTrace(); } return x; } }

I also tried (originally) to get it to write out using response.getWriter().write(), but I didn't have any luck. I figure if I can get this first, simple part working then everything should be easier after that.

Thanks for any assistance rendered.

glenn_penridge
October 16, 2015

Thanks guys, I'll give that a try today and see what kind of results that I can get.

I appreciate it. :)

Feike_Visser1
Adobe Employee
Adobe Employee
October 16, 2015

You miss the @Reference at this line:

private ResourceResolverFactory resolverFactory;

write it like this:

@Reference
private ResourceResolverFactory resolverFactory;