I want to get the HTML code / data of any website by using server-side javascript. How can I achieve this?
PS: I need this because from client-side javascript i can't do XMLHttpRequest of external domains due to the same origin policy.
Here is a Quick-n-Dirty solution:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label id="labelURL">
<xp:this.value>
<![CDATA[#{javascript:
var url:java.net.URL = new java.net.URL("http://google.com");
url.openConnection();
var is:java.io.InputStream = url.openStream();
var c;
var result = "";
while( (c = is.read()) != (-1) ){
result += #Char(c);
}
is.close();
result
}]]>
</xp:this.value>
</xp:label>
</xp:view>
A better solution accessing remote urls is to use http://hc.apache.org/httpclient-3.x/
A little less Q&D way is described here. It uses, as Sven suggested, the Apache HTTP client which provides authentication, automatic redirects etc.
Related
I want to create a xml file using SSJS on server. Is there a way to do so? Can anyone please give a sample code to create a xml file on server.
There are quite some ways. The seemingly easiest one is to create a string that looks like XML.
The next one would be the use of Java DOM classes. There is an article describing it.
Finally you can use SAX with a little helper class
Let us know how it goes.
Update: This would be my version of #Michael's code sample:
<?xml version="1.0" encoding="UTF-8"?>
<!-- XPage which is not rendered but returns data like XML, JSON, etc. -->
<!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn -->
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.beforeRenderResponse><![CDATA[#{javascript:try {
var out = facesContext.getOutputStream();
var exCon = facesContext.getExternalContext();
var response = exCon.getResponse(); // get the response context
// set content type, e.g. ...
response.setContentType("text/xml");
// set caching option
response.setHeader("Cache-Control", "no-cache");
// write XML output ...
var result = new biz.taoconsulting.xmltools.SimpleXMLDoc();
result.setOut(out);
result.openTag("result");
result.dateTag("created", new java.util.Date());
result.addSimpleTag("Author",#UserName);
result.openTag("FruitList");
result.addComment("Stephan really likes the fruits example");
var attributes = new java.util.HashMap();
attributes.add("name","Durian");
attributes.add("color","white");
attributes.add("taste","Don't ask");
result.addEmptyTag("fruit",attributes);
result.closeDocument();
// close the output
exCon.responseComplete();
out.close();
} catch (e) {
print(e.toString());
}}]]>
</xp:this.beforeRenderResponse>
</xp:view>
Note the differences here:
I use the beforeRenderResponse event
Access to outputStream instead of writer (stream is not accessible in the afterRenderResponse event)
set the response complete to stop the page from further output, so you can simply type comments on the page what it does
use of the helper class
What seems a little odd when you read the source of the helper class: why not use the output stream in the constructor, so you won't miss it? - I would today add a second constructor with that, but the parameterless constructor allow me to define that class as a managed bean if I fancy that.
to "render" XML in a String as #Stefan suggested I would use the XAgent approach:
<?xml version="1.0" encoding="UTF-8"?>
<!-- XPage which is not rendered but returns data like XML, JSON, etc. -->
<!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn -->
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.afterRenderResponse><![CDATA[#{javascript:try {
var writer = facesContext.getResponseWriter(), // get a writer object
response = facesContext.getExternalContext().getResponse(); // get the response context
// set content type, e.g. ...
response.setContentType("text/xml");
// set caching option
response.setHeader("Cache-Control", "no-cache");
// write XML output ...
writer.write(
'<?xml version="1.0"?>\n'
+ '<root>\n'
+ '<entity>Example Content</entity>\n'
+ '</root>\n'
);
// close the stream
writer.endDocument();
} catch (e) {
print(e.toString());
}}]]>
</xp:this.afterRenderResponse>
<xp:this.resources>
<xp:script src="/XBAN.jss" clientSide="false"></xp:script>
</xp:this.resources>
</xp:view>
Simply put his code into a newly created XPage and test it. Modify the lines in writer.write() to fit to your needs.
I have a xpage that use view.postscript like this:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.resources>
<xp:dojoModule name="dojox.widget.Toaster"></xp:dojoModule>
<xp:styleSheet href="/.ibmxspres/dojoroot/dojox/widget/Toaster/Toaster.css"></xp:styleSheet>
</xp:this.resources>
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[var Toaster = function(id, msg, type, duration, pos) {
type = (type == null) ? "message" : type;
duration = (duration == null) ? "5000" : duration;
pos = (pos == null) ? "br-up" : pos;
var obj = dijit.byId(id);
obj.positionDirection = pos;
obj.setContent(msg, type, duration);
obj.show();
}]]></xp:this.value>
</xp:scriptBlock>
<xp:div id="toaster" themeId="toaster" dojoType="dojox.widget.Toaster"></xp:div>
<xp:button value="Toaster" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:view.postScript("Toaster('"+getComponent("toaster").getClientId(facesContext)+"', 'toaster message!')");}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
But when I click button,the toaster can't show.Why?
And I need a way to show the toaster called by ssjs function.
Thanks a lot.
As #Frantisek Kossuth said, you're re-submitting the page. When your refreshMode is complete it will re-render the page based on the server values. If you want to make client side changes and reflect them in your UI, you can't do a refresh of complete. Doing a partial refresh of the page on an element that won't change (like button1) should update your UI without rebuilding the page.
Similarly, why do you need this to be done through SSJS? Why not just use Client actions in your button activation? If this isn't part of a larger function call that you're not including, simply change the event code from Server to Client and call the Toaster function that way. This would also allow you to not have to submit anything, leaving submit="false" in your eventHandler to avoid unnecessary functionality.
I'm having a problem trying to set values on a mobile page before transition into that page.
I have a scriptblock based on Tony McGuckin's OpenNTF XSnippet. http://openntf.org/XSnippets.nsf/snippet.xsp?id=calling-server-side-jscode-during-mobile-page-transitions
So when I transition to a page with the ID of "appPage3" I call the method "facilityCheckIn" if the JSON-RPC service.
I'm trying to set the value in a viewScoped managed bean and for testing am trying to set a normal viewScope variable.
As best as I can tell the Mobile Page is not picking up the changes. It's not showing the viewScope at all. I'm not sure what's up with that.
I believe the managed bean is getting it's value but it's like the page is getting rendered first. The value on the Mobile page is blank the first time
and then if I either refresh, or exit and go back to the page it does display. I tried accessing the bean via SSJS and EL.
I really need to be able to set values for mobile pages as I transition into and out of a page.
Any advice would be appreciated.
Thanks!!
I've updated the code below to show the complete Mobile Page. I've not included anything for the custom control that should be displaying the fields but can if necessary.
I've created a 6ish minute video demonstrating the problem and that also shows all the relevant code.
http://traffic.libsyn.com/notesin9/SO-Question.mp4
Thanks!!!
<xp:this.resources>
<xp:styleSheet href="/.ibmxspres/dojoroot/dijit/themes/tundra/tundra.css"></xp:styleSheet>
<xp:styleSheet href="/mobile.css"></xp:styleSheet>
</xp:this.resources>
<xc:ccDebugToolbar defaultCollapsed="false"
collapseTo="left"></xc:ccDebugToolbar>
<xe:singlePageApp id="singlePageApp1"
selectedPageName="home">
<xe:djxmHeading id="djxmHeading1" label="My Inventory"></xe:djxmHeading>
<xe:appPage id="homeID" pageName="home">
<xe:djxmHeading id="djxmHeading2" label="My Inventory">
</xe:djxmHeading>
<xc:mob_menu_home></xc:mob_menu_home>
</xe:appPage>
<xe:appPage id="appPage2" pageName="facility" resetContent="true">
<xc:mob_menu_facility></xc:mob_menu_facility>
</xe:appPage>
<xe:appPage id="appPage8" pageName="show" resetContent="true">
<xc:mob_menu_show></xc:mob_menu_show>
</xe:appPage>
<xe:appPage id="appPage3" pageName="facilityCheckIn"
resetContent="true">
<xc:mob_page_CheckInOut header="Check In at Facility"
scanType="Receiving" scanLocation="Facility">
</xc:mob_page_CheckInOut>
</xe:appPage>
<xe:appPage id="appPage5" pageName="facilityCheckOut"
resetContent="true">
<xc:mob_page_CheckInOut header="Check Out from Facility"
scanType="Shipping" scanLocation="Facility">
</xc:mob_page_CheckInOut>
</xe:appPage>
<xe:appPage id="appPage6" pageName="showCheckOut"
resetContent="true">
<xc:mob_page_CheckInOut header="Check Out from Show"
scanType="Shipping" scanLocation="Show">
</xc:mob_page_CheckInOut>
</xe:appPage>
<xe:appPage id="appPage7" pageName="showCheckIn"
resetContent="true">
<xc:mob_page_CheckInOut header="Check In at Show"
scanType="Receiving" scanLocation="Show">
</xc:mob_page_CheckInOut>
</xe:appPage>
<!-- SUB PAGES -->
<!-- GET MANIFEST Page -->
<xe:appPage id="appPage4" pageName="manifest" resetContent="true">
<xc:mob_page_Manifest></xc:mob_page_Manifest>
</xe:appPage>
</xe:singlePageApp>
<xe:jsonRpcService id="jsonRpcService1" serviceName="appService">
<xe:this.methods>
<xe:remoteMethod name="setCurrentPage">
<xe:this.arguments>
<xe:remoteMethodArg name="pageName"></xe:remoteMethodArg>
<xe:remoteMethodArg name="direction"></xe:remoteMethodArg>
</xe:this.arguments>
<xe:this.script><![CDATA[print("PageName " + pageName);
print("Direction " + direction);
viewScope.put("vsPage", "test");
App.setCurrentPage(pageName);
App.setCurrentDirection(direction);
return "";]]></xe:this.script>
</xe:remoteMethod>
</xe:this.methods>
</xe:jsonRpcService>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[
XSP.addOnLoad(function(){
// Begin App Page 1
var newPage = dijit.byId("#{id:appPage3}");
if(null != newPage){
dojo.connect(newPage, "onBeforeTransitionIn", function(){
var deferred = appService.setCurrentPage("facilityCheckIn", "onBeforeTransitionIn");
deferred.addCallback(function(result) {
console.log(result);
});
});
dojo.connect(newPage, "onBeforeTransitionOut", function(){
var deferred = appService.setCurrentPage("facilityCheckIn", "onBeforeTransitionOut");
deferred.addCallback(function(result) {
console.log(result);
});
});
dojo.connect(newPage, "onAfterTransitionIn", function(){
var deferred = appService.setCurrentPage("facilityCheckIn", "onAfterTransitionIn");
deferred.addCallback(function(result) {
console.log(result);
});
});
dojo.connect(newPage, "onAfterTransitionOut", function(){
var deferred =appService.setCurrentPage("facilityCheckIn", "onAfterTransitionOut");
deferred.addCallback(function(result) {
console.log(result);
});
});
}
// End App Page 1
// Begin Home Page
var newPage = dijit.byId("#{id:homeID}");
if(null != newPage){
//console.log("Inside home Page")
dojo.connect(newPage, "onBeforeTransitionIn", function(){
var deferred = appService.homePageReset();
deferred.addCallback(function(result) {
console.log(result);
});
});
dojo.connect(newPage, "onBeforeTransitionOut", function(){
var deferred = appService.homePageReset();
deferred.addCallback(function(result) {
console.log(result);
});
});
}
// END Home Page
// Insert new Code ABOVE THIS LINE
}); // This ends the block that holds all the functions
]]></xp:this.value>
</xp:scriptBlock>
I was faced with a similar problem some time ago and I had to create another XPage (with a SingleApplication) to navigate to instead of just jumping to an appPage within the same SingleApplication.
Not ideal, however, it also solved another issue for me since I wanted to be able to jump directly to the page in question (using a QR code).. ;-)
/John
PS. Will follow your findings here to see if it can be done. This kind of issues with the mobile controls (I had some with typeahead as well) sort of pushed me in direction of other frameworks, for now, anyway...
David.... You said that doing a refresh did correct the issue, also Stephan mentioned that the transition to the new page happens before the result comes back from the RPC which I think is correct. So in your callback, while not optimal but may at least get you moving forward, you could fire off a partial refresh by using:
XSP.partialRefreshGet("#{id:appPage3}",{});
//I've had partial success with the "#{id:appPage3}" call, so I usually use a full
// dojo query like:
var appPageId = dojo.query("[id$='appPage3']")[0].id
I don't know if that will correct your issue, but it appears everything is working as it should with the exception of that value being populated.
Ok I believe I have this solved. I had no luck using the RPC control stuff from Tony's XSnippet. That works of you're leaving the page but not if your entering. This seems to work as desired.
To deal with entering you need to put your code in the Rendering event of the header.
I wonder if I can get the parameters and/or properties of an xpage or custom control programmatically.
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" id="layout">
<xp:this.properties>
<xp:parameter name="testcc.xsp" value="Test 1"></xp:parameter>
<xp:parameter name="index.xsp" value="Main"></xp:parameter>
</xp:this.properties>
...
How can I access this parameter list to use it e.g. in a repeat control?
EDIT
You both are right, thank you! But this works only on a page, not in a custom control.
EDIT
You both are great :-)
BUT: I should revise my question:
I have a custom control where I defined the properties. Within the SAMe custom control I want to access these properties in a repeat control.
Both your answers seem to assume that the access to these properties is from the view (page) level, right?
I tested Svens way - this works if I access the props in the CC from the page level.
EDIT
So this is the code of the CC:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.properties>
<xp:parameter name="param" value="val"></xp:parameter>
</xp:this.properties>
<xp:label value="#{javascript:facesContext.getProperty('param')}"
id="label1">
</xp:label>
</xp:view>
As you can see I just want to access the property within the CC itselt, not from the page level.
You can get the properties by accessing facesContext:
facesContext.getProperty("index.xsp")
EDIT:
If you set the properties in a custom control, the properties are not added to the view root. The are set as attributes of the custom control (com.ibm.xsp.component.UIIncludeComposite).
To access them you first have to give your CC an Id:
<xc:ccProp id="myId" />
This allows you to access the custom control like a component with the getComponent() method and retrieve the attribute properties which contains the properties:
<xp:label id="labelProperty">
<xp:this.value><![CDATA[#{javascript:
var cc:com.ibm.xsp.component.UIIncludeComposite = getComponent("myId");
var arrList:java.util.ArrayList = cc.getAttributes().get("properties");
arrList.get(0).getName()}]]>
</xp:this.value>
</xp:label>
EDIT 2:
You can access the CC (which is the parent of the label in this example) this way if you don't want to give your CC an ID:
Code of the custom control:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.properties>
<xp:parameter name="param" value="val"></xp:parameter>
</xp:this.properties>
<xp:label id="label1">
<xp:this.value><![CDATA[#{javascript:
this.parent.getAttributes().get("properties").get(0).getName()
}]]></xp:this.value>
</xp:label>
<xp:label id="label2">
<xp:this.value><![CDATA[#{javascript:
this.parent.getAttributes().get("properties").get(0).getValue()
}]]></xp:this.value>
</xp:label>
</xp:view>
Hope this helps to clarify the issue.
To get the property list you can use the view.getProperties(). It returns an object of java.util.List which you can use to loop through individual properties (which are objects of com.ibm.xsp.complex.Parameter). Below is the snippet.
var allProperties:java.util.List = view.getProperties();
for (var i=0 ; i<allProperties.size() ; i++) {
var property:com.ibm.xsp.complex.Parameter = allProperties.get(i);
// property.getName();
// property.getValue();
}
If you want to put it in a repeat then you can bind it to view.getProperties() and then get its individual values. You code would then look something like this:
<xp:repeat rows="30" value="#{javascript:view.getProperties()}" var="property">
<xp:text escape="true">
<xp:this.value><![CDATA[#{javascript:property.getName() + " - " + property.getValue();}]]></xp:this.value>
</xp:text>
<xp:br></xp:br>
</xp:repeat>
If you've got values that you want to use on the various parts of an Xpage, whether directly on the page, in a custom control, or in a repeat, I would recommend that you put the values into sessionScope variables. This allows you to change them easily as the user enters information on the Xpage.
For example, sessionScope.PODocUNID = poDoc.getDocument().getUniversalID(); would put the UNID of the purchase order document that I'm working with into a sessionScope variable named PODocUNID. Then, you can pull up the value any time you want by simply referencing sessionScope.PODocUNID in your code.
Alternatively, you could use Russ Maher's current favorite toy, the Managed Bean (see his three-part video on Notes in 9, starting at: http://notesin9.com/index.php/2012/11/02/notesin9-084-sharing-managed-beans-in-xpages/ )
I am trying to post an update i.e. a status message to IBM Connections using the extlib.
I have used the extlib with connectionsLTPA endpoint which works really well for getting the communities list. However I wish to add functionality to update the users status.
So far I have tried using
<xp:this.data>
<xe:connectionsData var="connectionsData1"
endpoint="connections" serviceUrl="/profiles/atom/mv/theboard/entry/status.do?email=#{userBean.email}">
</xe:connectionsData>
</xp:this.data>
and then in the event handler
var sb = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<author><name>#{userBean.displayName}</name></author>" +
"<entry xmlns=\"http://www.w3.org/2005/Atom\">" +
"<content type=\"html\">" +input + "</content>" +
"<category scheme=\"http://www.ibm.com/xmlns/prod/sn/type\" term=\"status\" />"+
"</entry>\r\n";
var output = #{connectionsData1}.post(null, sb, "xml");
however this throws an error trying to call post on the binded data point.
Anybody able to point me in the right direction?
Thanks
I have found that implementing the sbt by doing the follwing:
<xp:button id="button2">
<xp:this.value>Update my status</xp:this.value>
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial">
<xp:this.action><![CDATA[#{javascript:try {
var svc = new sbt.ConnectionsService("/profiles/atom/mv/theboard/entry/status.do?email=" +userBean.email);
var sb = new java.lang.StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.append("<entry xmlns=\"http://www.w3.org/2005/Atom\">");
sb.append("<category scheme=\"http://www.ibm.com/xmlns/prod/sn/type\" term=\"entry\"/>");
sb.append("<category scheme=\"http://www.ibm.com/xmlns/prod/sn/message-type\" term=\"status\"></category>");
sb.append("<content type=\"text\">");
sb.append(getComponent("inputText1").getValue());
sb.append("</content>");
sb.append("</entry>");
var msg = svc.put(null, sb.toString(),"xml");
var msg = "updated users profile status";
#WarningMessage(msg)
} catch(e) {}
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
The reason it wasn't working correctly is that the atom feed needed to be declared as an entry. This article in the connections doc for 2.5 http://publib.boulder.ibm.com/infocenter/ltscnnct/v2r0/index.jsp?topic=/com.ibm.connections.25.help/r_api_prof_update_photo.html explains the required parts of the xml atom document.