This may be more of a rant than a question that can actually be answered. I'm not sure yet. I suspect it may be a situation that lots of people encounter though so hopefully it's a useful question.
We have jsps that present information that can be in about 40 different statuses. Let's say it's the status of a complicated financial product. So we want to output messages that are dependent on the status, for example status 10 might be "Your product is pending activation" and status 15 might be "Your product is active" and so on.
So it would seem that we could have a simple lookup that returns the appropriate messages depending on the status and it all works neatly.
But in reality, the status alone is not enough to determine the right message. If it's status 10 (pending activation) but it's within 1 week of the activation then we want to color the message red. If it's status 10 (pending activation) but there's an external reason delaying it, we want a message that provides a link to an explanation page. And so on.
So the status by itsef doesn't capture all the information needed to determine and create the message. There are lots of other extraneous pieces of information that are also required.
The way the legacy code works, all these pieces of information are loaded into the jsp, and then the jsp makes determinations based on this non-status information.
Now that we are redoing the site, I'm faced with the situation that we need this same status logic in multiple different places, but outputting different wrapping html.
In short, it's a big mess.
I think the ideal answer would be to refactor things so that all the decisions are taken out of the jsps. Ugh, I'm not sure what the correct way to handle it is. There's a lot of stringy complexity and I'm not sure where to start.
I'm not sure I've given enough detail to even make the problem clear, but if anyone has any advice, I'd be very grateful..
EDIT: Thanks for all your answers! The code is so tangly that I've sort of refactored it a bit by pulling common code into include files, so that I can include those files where they're needed. I'll definitely look at encapsulating things further with functions as you suggest. Will circle back round to your answers soon. Thanks again.
I believe your existing JSPs are using a lot of <% // scriptlets %> to achieve at the final status message. I suggest you write a custom tag that factors all of that Java logic out of the JSP.
Handling message content
Implement the tag so that it takes anything that's required to generate the message (like your Product object itself) as one of its attributes.
WEB-INF/status.tld (Tag library descriptor)
<taglib ... >
<uri>WEB-INF/status.tld</uri>
<tag>
<name>statusMesg</name>
<tag-class>com.foo.StatusMesgTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>product</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>com.foo.beans.Product</type>
</attribute>
</tag>
</taglib>
Implement the Tag class with the Java code that's currently present in your scriptlets.
pubic class StatusMesgTag extends SimpleTagSupport {
private Product product;
public void setProduct(Product product) {
this.product = product;
}
public void doTag() throws JspException, IOException {
StringBuilder statusMesg = new StringBuilder();
// process Product info to generate mesg
getJspContext().getOut().println(statusMesg);
}
}
Then invoke it in your JSP (with the Product object mapped as "product" in any one of your page, request or session scopes) as follows
<custom:statusMesg product="${product}" />
after adding the taglib directive to your JSP
<%# taglib prefix="custom" uri"WEB-INF/status.tld" %>
Handling message rendering (view)
The part where you need to decide the colour the message should be rendered in should be handled with CSS stylesheets. You could have your custom tag determine the message priority and then return your message with an appropriate CSS style class like
<span class="priorityHigh">Needs activation within 1 week</span>
Your CSS would map different priorities to different colours like
.priorityHigh {color: red};
.priorityNormal {color: black};
.priorityLow {color: green};
Create one Util class with a method to receive by parameter the status, date, etc... So the return of the method will be an object with properties for all the info that the jsp will need to render it.
Something like this:
class MyStatusUtil{
public static StatusInfo getStatusInfo(int status, Date date, etc...){
StatusInfo info = new StatusInfo();
if(status==10){
info.setStatusName("....");
}
.....
if(date==....){
info.setColor("...");
}
if(somethinElse){
info.setComment("....");
}
return info;
}
}
StatusInfo class:
class StatusInfo{
private String statusName;
private String color;
private String comment;
}
jsp:
<% StatusInfo info = MyStatusUtil.getStatusInfo(....)
//now render the html based on the StatusInfo data.
%>
Can you use a custom jstl tag with a couple parameters?
Related
I am very new to coding in Java/Android Studio. I have everything setup that I have been able to figure out thus far. I have a button, and I need to put code inside of the button click event that will fetch information from a website, convert it to a string and display it. I figured I would have to use the html source code in order to do this, so I have installed Jsoup html parser. All of the help with Jsoup I have found only leads me up to getting the HTML into a "Document". And I am not sure if that is the best way to accomplish what I need. Can anyone tell me what code to use to fetch the html code from the website, and then do a search through the html looking for a specific match, and convert that match to a string. Or can anyone tell me if there is a better way to do this. I only need to grab one piece of information and display it.
Here is the piece of html code that contains the value I want:
writeBidRow('Wheat',-60,false,false,false,0.5,'01/15/2015','02/26/2015','All',' ',' ',60,'even','c=2246&l=3519&d=G15',quotes['KEH15'], 0-0);
I need to grab and display whatever value represents the quotes['KEH15'], in that html code.
Thank you in advance for your help.
Keith
Grabbing raw HTML is an extremely tedious way to access information from the web, bad practice, and difficult to maintain in the case that wherever you are fetching the info from changes their HTML.
I don't know your specific situation and what the data is that you are fetching, but if there is another way for you to fetch that data via an API, use that instead.
Since you say you are pretty new to Android and Java, let me explain something I wish had been explained to me very early on (although I am mostly self taught).
The way people access information across the Internet is traditionally through HTML and JavaScript (which is interpreted by your browser like Chrome or Firefox to look pretty), which are transferred over the internet using the protocol called HTTP. This is a great way for humans to communicate with computers that are far away, and the average person probably doesn't realize that there is more to the internet than this--your browser and the websites you can go to.
Although there are multiple methods, for the purpose of what I think you're looking for, applications communicate over the internet a slightly different way:
When an android application asks a server for some information, rather than returning HTML and JavaScript which is intended for human consumption, the server will (traditionally) return what's called JSON (or sometimes XML, which is very similar). JSON is a very simple way to get information about an object, and put it into a form that is readable easily by both humans (developers) and computers, and can be transmitted over the internet easily. For example, let's say you ask a server for some kind of "Video" object for an app that plays video, it may give you something like this:
{
"name": "Gangnam Style",
"metadata": {
"url": "https://www.youtube.com/watch?v=9bZkp7q19f0",
"views": 2000000000,
"ageRestricted": false,
"likes": 43434
"dislikes":124
},
"comments": [
{
"username": "John",
"comment": "10/10 would watch again"
},
{
"username": "Jane",
"number": "12/10 with rice"
}
]
}
That is very readable by us humans, but also by computers! We know the name is "Gangnam Style", the link of the video, etc.
A super helpful way to interact with JSON in Java and Android is Google's GSON library, which lets you cast a Java object as JSON or parse a JSON object to a Java object.
To get this information in the first place, you have to make a network call to an API, Application Programming Interface. Just a fancy term for communication between a server and a client. One very cool, free, and easy to understand API that I will use for this example is the OMDB API, which just spits back information about movies from IMDB. So how do you talk to the API? Well luckily they've got some nice documentation, which says that to get information on a movie we need to use some parameters in the url, like perhaps
http://www.omdbapi.com/?t=Interstellar
They want a title with the parameter "t". We could put a year, or return type, but this should be good to understand the basics. If you go to that URL in your browser, it spits back lots of information about Interstellar in JSON form. That stuff we were talking about! So how would you get this information from your Android application?
Well, you could use Android's built in HttpUrlConnection classes and research for a few hours on why your calls aren't working. But doesn't essentially every app now use networking? Why reinvent the wheel when virtually every valuable app out there has probably done this work before? Perhaps we can find some code online to do this work for us.
Or even better, a library! In particular, an open source library developed by Square, retrofit. There are multiple libraries like it (go ahead and research that out, it's best to find the best fit for your project), but the idea is they do all the hard work for you like low level network programming. Following their guides, you can reduce a lot of code work into just a few lines. So for our OMDB API example, we can set up our network calls like this:
//OMDB API
public ApiClient{
//an instance of this client object
private static OmdbApiInterface sOmdbApiInterface;
//if the omdbApiInterface object has been instantiated, return it, but if not, build it then return it.
public static OmdbApiInterface getOmdbApiClient() {
if (sOmdbApiInterface == null) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://www.omdbapi.com")
.build();
sOmdbApiInterface = restAdapter.create(OmdbApiInterface.class);
}
return sOmdbApiInterface;
}
public interface OmdbApiInterface {
#GET("/")
void getInfo(#Query("t") String title, Callback<JsonObject> callback);
}
}
After you have researched and understand what's going on up there using their documentation, we can now use this class that we have set up anywhere in your application to call the API:
//you could get a user input string and pass it in as movieName
ApiClient.getOmdbApiClient().getInfo(movieName, new Callback<List<MovieInfo>>() {
//the nice thing here is that RetroFit deals with the JSON for you, so you can just get information right here from the JSON object
#Override
public void success(JsonObject movies, Response response) {
Log.i("TAG","Movie name is " + movies.getString("Title");
}
#Override
public void failure(RetrofitError error) {
Log.e("TAG", error.getMessage());
}
});
Now you've made an API call to get info from across the web! Congratulations! Now do what you want with the data. In this case we used Omdb but you can use anything that has this method of communication. For your purposes, I don't know exactly what data you are trying to get, but if it's possible, try to find a public API or something where you can get it using a method similar to this.
Let me know if you've got any questions.
Cheers!
As #caleb-allen said, if an API is available to you, it's better to use that.
However, I'm assuming that the web page is all you have to work with.
There are many libraries that can be used on Android to get the content of a URL.
Choices range from using the bare-bones HTTPUrlConnection to slightly higher-level HTTPClient to using robust libraries like Retrofit. I personally recommend Retrofit. Whatever you do, make sure that your HTTP access is asynchronous, and not done on the UI thread. Retrofit will handle this for you by default.
For parsing the results, I've had good results in the past using the open-source HTMLCleaner library - see http://htmlcleaner.sourceforge.net
Similar to JSoup, it takes a possibly-badly-formed HTML document and creates a valid XML document from it.
Once you have a valid XML document, you can use HTMLCleaner's implementation of the XML DOM to parse the document to find what you need.
Here, for example, is a method that I use to parse the names of 'projects' from a <table> element on a web page where projects are links within the table:
private List<Project> parseProjects(String html) throws Exception {
List<Project> parsedProjects = new ArrayList<Project>();
HtmlCleaner pageParser = new HtmlCleaner();
TagNode node = pageParser.clean(html);
String xpath = "//table[#class='listtable']".toString();
Object[] tables = node.evaluateXPath(xpath);
TagNode tableNode;
if(tables.length > 1) {
tableNode = (TagNode) tables[0];
} else {
throw new Exception("projects table not found in html");
}
TagNode[] projectLinks = tableNode.getElementsByName("a", true);
for(int i = 0; i < projectLinks.length; i++) {
TagNode link = projectLinks[i];
String projectName = link.getText().toString();
String href = link.getAttributeByName("href");
String projectIdString = href.split("=")[1];
int projectId = Integer.parseInt(projectIdString);
Project project = new Project(projectId, projectName);
parsedProjects.add(project);
}
return parsedProjects;
}
If you have permission to edit the webpage to add hyper link to specified line of that page you can use this way
First add code for head of line that you want to go there in your page
head your text if wanna
Then in your apk app on control click code enter
This.mwebview.loadurl("https:#######.com.html#target")
in left side of # enter your address of webpage and then #target in this example that your id is target.
Excuse me if my english lang. isn't good
Im trying to put some validation in the date field. The condition is the effective date field should be less or equal to the current date and it should be 1st of month.
Im doing it in tapestry.The data type is DATE. im using tapestry as yo know you will have .html page a, .java file and .page file. Im doing it in the java file . So please help me on this.
When the form is submitted t5 emits various events during the different stages. On EventConstants.VALIDATE is a good place to perform more complex validations that are not supported by t5 out of the box, or to perform cross-field validation serverside.
#Component
private Form myForm;
...
#OnEvent(value = EventConstants.VALIDATE, component = "myForm")
public void onCreateEditValidate() {
// do validation and if any error record it
myForm.record(theDateField, "Dang, try again!");
...
http://tapestry.apache.org/forms-and-validation.html
You can use the onValidate event too as stated at the end of the link jon martin solas posted.
Something like:
void onValidateFromYouDateFieldId(..) throws ValidationException{
//your custom validations
}
you can check out this example for more information:
http://jumpstart.doublenegative.com.au/jumpstart/examples/input/morevalidation
http://tapestry.apache.org/forms-and-validation.html#FormsandValidation-OverridingtheTranslatorwithEvents
From current JSP I need to open new page with sending to it POST data. How I can make it?
In other words I need redirect from one page to another, but I cant use sendRedirect(because only GET) and requestDispatcher(because context of pages are different)
You have to create <form method="post">, fill the fields with respective data and submit it by JavaScript.
But on the other hand, what is your reason for that? There probably exists a cleaner solution.
Just make the behaviour that would happen if the initial POST data is received the default behaviour of the JSP when no post data is received.
e.g (in pseudo code - I don't know Java)
if (is_set(POST) ) {
if(POST == expectedInitialVals) {
defaultBahaviour();
} else {
handleOtherValues();
}
} else {
defaultBahaviour();
}
If you also want to persist the POST data in the page set the values on the relevant form fields in the page in your JSP.
I have a mobile flow for registration that I want to use in my app, and I do not have control of the source --
I am looking for a way to grab a few pieces of data when the user finishes registering, (confirmation number, etc.) that will be sent to my app (hopefully via Android's addJavascriptInterface)
I am certain on one thing - the id of the element I need. The flow could change, and is already a few pages long, So I'm looking for a general solution. The basic Idea I'm hoping for is this:
Inject a JavaScript snippet to each page during shouldOverrideUrlLoading, which will automatically call my JavaScript Interface and check for the value of the field with the id I'm looking for. (or just return the entire HTML, and I'll do it in Java)
view.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//inject javascript here to get value
return false;
}});
I've seen tutorials on using addJavascriptInterface, but they all seem to assume some control or understanding of the 'single' page that will be navigated to. Since I have a potentially lengthy flow (3+ pages) and no control over the source, I am interested in hearing any suggestions.
Check URL of the current page and if it's the right one insert JavaScript in the curent page. With the help of Java-JS binding you could get some data out. See my previous answer: Determine element of url from webview shouldOverRideUrlLoading
What's the best way to externalize large quantities of HTML in a GWT app? We have a rather complicated GWT app of about 30 "pages"; each page has a sort of guide at the bottom that is several paragraphs of HTML markup. I'd like to externalize the HTML so that it can remain as "unescaped" as possible.
I know and understand how to use property files in GWT; that's certainly better than embedding the content in Java classes, but still kind of ugly for HTML (you need to backslashify everything, as well as escape quotes, etc.)
Normally this is the kind of thing you would put in a JSP, but I don't see any equivalent to that in GWT. I'm considering just writing a widget that will simply fetch the content from html files on the server and then add the text to an HTML widget. But it seems there ought to be a simpler way.
I've used ClientBundle in a similar setting. I've created a package my.resources and put my HTML document and the following class there:
package my.resources;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.TextResource;
public interface MyHtmlResources extends ClientBundle {
public static final MyHtmlResources INSTANCE = GWT.create(MyHtmlResources.class);
#Source("intro.html")
public TextResource getIntroHtml();
}
Then I get the content of that file by calling the following from my GWT client code:
HTML htmlPanel = new HTML();
String html = MyHtmlResources.INSTANCE.getIntroHtml().getText();
htmlPanel.setHTML(html);
See http://code.google.com/webtoolkit/doc/latest/DevGuideClientBundle.html for further information.
You can use some templating mechanism. Try FreeMarker or Velocity templates. You'll be having your HTML in files that will be retrieved by templating libraries. These files can be named with proper extensions, e.g. .html, .css, .js obsearvable on their own.
I'd say you load the external html through a Frame.
Frame frame = new Frame();
frame.setUrl(GWT.getModuleBase() + getCurrentPageHelp());
add(frame);
You can arrange some convention or lookup for the getCurrentPageHelp() to return the appropriate path (eg: /manuals/myPage/help.html)
Here's an example of frame in action.
In GWT 2.0, you can do this using the UiBinder.
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'>
<div>
Hello, <span ui:field='nameSpan’/>, this is just good ‘ol HTML.
</div>
</ui:UiBinder>
These files are kept separate from your Java code and can be edited as HTML. They are also provide integration with GWT widgets, so that you can easily access elements within the HTML from your GWT code.
GWT 2.0, when released, should have a ClientBundle, which probably tackles this need.
You could try implementing a Generator to load external HTML from a file at compile time and build a class that emits it. There doesn't seem to be too much help online for creating generators but here's a post to the GWT group that might get you started: GWT group on groups.google.com.
I was doing similar research and, so far, I see that the best way to approach this problem is via the DeclarativeUI or UriBind. Unfortunately it still in incubator, so we need to work around the problem.
I solve it in couple of different ways:
Active overlay, i.e.: you create your standard HTML/CSS and inject the GET code via <script> tag. Everywhere you need to access an element from GWT code you write something like this:
RootPanel.get("element-name").setVisible(false);
You write your code 100% GWT and then, if a big HTML chunk is needed, you bring it to the client either via IFRAME or via AJAX and then inject it via HTML panel like this:
String html = "<div id='one' "
+ "style='border:3px dotted blue;'>"
+ "</div><div id='two' "
+ "style='border:3px dotted green;'"
+ "></div>";
HTMLPanel panel = new HTMLPanel(html);
panel.setSize("200px", "120px");
panel.addStyleName("demo-panel");
panel.add(new Button("Do Nothing"), "one");
panel.add(new TextBox(), "two");
RootPanel.get("demo").add(panel);
Why not to use good-old IFRAME? Just create an iFrame where you wish to put a hint and change its location when GWT 'page' changes.
Advantages:
Hits are stored in separate maintainable HTML files of any structure
AJAX-style loading with no coding at all on server side
If needed, application could still interact with loaded info
Disadvantages:
Each hint file should have link to shared CSS for common look-and-feel
Hard to internationalize
To make this approach a bit better, you might handle loading errors and redirect to default language/topic on 404 errors. So, search priority will be like that:
Current topic for current language
Current topic for default language
Default topic for current language
Default error page
I think it's quite easy to create such GWT component to incorporate iFrame interactions
The GWT Portlets framework (http://code.google.com/p/gwtportlets/) includes a WebAppContentPortlet. This serves up any content from your web app (static HTML, JSPs etc.). You can put it on a page with additional functionality in other Portlets and everything is fetched with a single async call when the page loads.
Have a look at the source for WebAppContentPortlet and WebAppContentDataProvider to see how it is done or try using the framework itself. Here are the relevant bits of source:
WebAppContentPortlet (client side)
((HasHTML)getWidget()).setHTML(html == null ? "<i>Web App Content</i>" : html);
WebAppContentDataProvider (server side):
HttpServletRequest servletRequest = req.getServletRequest();
String path = f.path.startsWith("/") ? f.path : "/" + f.path;
RequestDispatcher rd = servletRequest.getRequestDispatcher(path);
BufferedResponse res = new BufferedResponse(req.getServletResponse());
try {
rd.include(servletRequest, res);
res.getWriter().flush();
f.html = new String(res.toByteArray(), res.getCharacterEncoding());
} catch (Exception e) {
log.error("Error including '" + path + "': " + e, e);
f.html = "Error including '" + path +
"'<br>(see server log for details)";
}
You can use servlets with jsps for the html parts of the page and still include the javascript needed to run the gwt app on the page.
I'm not sure I understand your question, but I'm going to assume you've factored out this common summary into it's own widget. If so, the problem is that you don't like the ugly way of embedding HTML into the Java code.
GWT 2.0 has UiBinder, which allows you to define the GUI in raw HTMLish template, and you can inject values into the template from the Java world. Read through the dev guide and it gives a pretty good outline.
Take a look at
http://code.google.com/intl/es-ES/webtoolkit/doc/latest/DevGuideClientBundle.html
You can try GWT App with html templates generated and binded on run-time, no compiling-time.
Not knowing GWT, but can't you define and anchor div tag in your app html then perform a get against the HTML files that you need, and append to the div? How different would this be from a micro-template?
UPDATE:
I just found this nice jQuery plugin in an answer to another StackOverflow question.