Use router in Rest API - java - java

package firstREST;
import org.restlet.Application;
import org.restlet.Component;
import org.restlet.Restlet;
import org.restlet.data.Protocol;
import org.restlet.routing.Router;
public class Faculty extends Application {
public static void main(String[] args) {
Component comp = new Component();
comp.getServers().add(Protocol.HTTP, 8080);
Application app = new Faculty();
comp.getDefaultHost().attach(app);
try {
comp.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/attendance/faculty/select", Faculty_Get.class);
router.attach("/attendance/faculty/insert", Faculty_Insert.class);
return router;
}
}
the above code is not working. after running the server when i open a url http://localhost:8080/attendance/faculty/select it won't work. How can i make this work? anyone can help?
Faculty_Get Class:
package firstREST;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.*;
public class Faculty_Get extends ServerResource {
#Get ("json")
public String present( String name ) throws Exception {
// Values.
String getName = null;
String getPost = null;
String getCourse = null;
String getDepartment = null;
String getPresents = null;
String getAbsents = null;
// Get values.
String jSonString = getQuery().getValues( "data" );
// Decode jSon.
JSONArray mJsonArray = new JSONArray( jSonString );
JSONObject mJsonObject = new JSONObject();
for ( int i = 0; i < mJsonArray.length(); i++ ) {
mJsonObject = mJsonArray.getJSONObject(i);
getName = mJsonObject.getString( "name" );
}
// Database.
try
{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection myconn = DriverManager.getConnection("jdbc:mysql://localhost:3306/attendance", "root", "");
PreparedStatement ps = myconn.prepareStatement("SELECT * FROM faculty where name = '" + getName + "'");
ResultSet rs = ps.executeQuery();
while( rs.next() )
{
getName = rs.getString( "name" );
getPost = rs.getString( "post" );
getCourse = rs.getString( "course" );
getDepartment = rs.getString( "department" );
getPresents = rs.getString( "presents" );
getAbsents = rs.getString( "absents" );
}
return "name="+getName+"&post="+getPost+"&course="+getCourse+"&department="+getDepartment+"&presents="+getPresents+"&absents="+getAbsents;
}
catch(Exception e)
{
throw e;
}
}
}
Error:
May 18, 2015 6:17:10 PM org.restlet.resource.UniformResource doCatch
WARNING: Exception or error caught in resource
java.lang.NullPointerException
at java.io.StringReader.<init>(Unknown Source)
at org.json.JSONTokener.<init>(JSONTokener.java:83)
at org.json.JSONArray.<init>(JSONArray.java:145)
at firstREST.Faculty_Get.present(Faculty_Get.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.restlet.resource.ServerResource.doHandle(ServerResource.java:449)
at org.restlet.resource.ServerResource.get(ServerResource.java:648)
at org.restlet.resource.ServerResource.doHandle(ServerResource.java:530)
at org.restlet.resource.ServerResource.doNegotiatedHandle(ServerResource.java:590)
at org.restlet.resource.ServerResource.doConditionalHandle(ServerResource.java:302)
at org.restlet.resource.ServerResource.handle(ServerResource.java:849)
at org.restlet.resource.Finder.handle(Finder.java:513)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Router.doHandle(Router.java:500)
at org.restlet.routing.Router.handle(Router.java:740)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:154)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.engine.ChainHelper.handle(ChainHelper.java:114)
at org.restlet.engine.application.ApplicationHelper.handle(ApplicationHelper.java:75)
at org.restlet.Application.handle(Application.java:391)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Router.doHandle(Router.java:500)
at org.restlet.routing.Router.handle(Router.java:740)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Router.doHandle(Router.java:500)
at org.restlet.routing.Router.handle(Router.java:740)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:154)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.routing.Filter.doHandle(Filter.java:159)
at org.restlet.routing.Filter.handle(Filter.java:206)
at org.restlet.engine.ChainHelper.handle(ChainHelper.java:114)
at org.restlet.Component.handle(Component.java:391)
at org.restlet.Server.handle(Server.java:491)
at org.restlet.engine.http.connector.BaseServerHelper.handle(BaseServerHelper.java:161)
at org.restlet.engine.http.connector.BaseServerHelper.handleInbound(BaseServerHelper.java:170)
at org.restlet.engine.http.connector.BaseHelper.handleNextInbound(BaseHelper.java:421)
at org.restlet.engine.http.connector.Connection.readMessages(Connection.java:698)
at org.restlet.engine.http.connector.Controller$2.run(Controller.java:98)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
May 18, 2015 6:17:10 PM org.restlet.engine.log.LogFilter afterHandle
INFO: 2015-05-18 18:17:10 127.0.0.1 - - 8080 GET /attendance/faculty/select - 500 486 0 30 http://localhost:8080 Mozilla/5.0 (Windows NT 6.1; rv:40.0) Gecko/20100101 Firefox/40.0 -
This is the error i am getting when i refresh my browser. I don't know what's causing this issue.

I think that you could make things much simpler and moreover your application isn't really RESTful ;-) I strongly think that using Restlet the right way will contribute to fix your issue. It seems that you use the method getQuery whereas you don't have query string. Moreover such query parameters don't seem to apply in such case.
Before going further, I would recommend you to have a look at this link to design a Web API / RESTful service: https://templth.wordpress.com/2014/12/15/designing-a-web-api/.
Here are the comments I would have regarding the code you provided in your questions:
You should use one resource for list resource and one for single resource. So I would something like that:
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/attendance/faculty/{name}", FacultyServerResource.class);
router.attach("/attendance/faculty/", FacultyListServerResource.class);
return router;
}
It's not RESTful to use operation names (like select or insert) within the resource path. You should leverage the existing HTTP methods for your needs.
The token {name} corresponds to a path variable. This means that the attached server resource will be called whatever the value. For example, URLs like /attendance/faculty/facultyName1 or /attendance/faculty/facultyName2 will match. In addition, Restlet will automatically set the value within the attribute name. For URL #1, name is facultyName1 and for URL #2, name is facultyName2.
The string you provide as first parameter of the method attach can be seen as a kind of regular expression.
You should use a path variable to specify the criterion (the faculty name) to load your faculty. See the element {name} within the resource path /attendance/faculty/{name}. Restlet will allow you to get simply this hint with its API. So I would adapt the code of your server resource as described below:
public class FacultyServerResource extends ServerResource {
#Get ("json")
public String present() throws Exception {
String facultyName = (String)getAttribute("name");
(...)
}
As a reminder, specifying the value json in the annotation Get allows to configuration content negotiation and says that this method will only be used if the client wants to receive a JSON content.
You should work on bean within the server resource regarding the returned content. You can simply return it from your method present. From your code, I would create a bean like that:
public class Faculty {
private String name;
private String post;
private String course;
private String department;
private List<String> presents;
private List<String> absents;
// Getters and setters
(...)
}
and update the method present:
#Get ("json")
public Faculty present() throws Exception {
(...)
Faculty faculty = new Faculty();
faculty.setName("...");
faculty.setPost("...");
(...)
return faculty;
}
To make work such approach, you simply need to add the extension org.restlet.ext.jackson (and its dependencies) within your classpath.
Something I don't understand in the server resource class is why you use the method getQuery. The latter is made to get hints from query parameters and must be typically used with URLs like this: /attendance/faculty/facultyName?param1=something&param2=somethingelse. You will get the parameter values like this:
String param1Value = getQuery().getValues("param1");
// or
String param2Value = getQueryValue("param2");
In you case, this will be null since you don't have query string / query parameters. I don't understand the purpose of your query parameter data.
Another thing that you should take into account is to use a connection pool since creating a JDBC connection to the database isn't efficient within Web environment. Moreover you can't limit the number of opened connection. There are tools like DBCP or C3P0 that provides such feature.
Hope it will help you and feel free to ask me if something isn't clear!
Thierry

Related

jcifs-krb5: "Server not found in Kerberos database", then it works

I have to connect to a CIFS share from a Java program without mounting it, so I took KerberosAuthExample from jcifs-krb5 and slightly modified it; here is the code:
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import com.sun.security.auth.module.Krb5LoginModule;
import jcifs.Config;
import jcifs.smb.Kerb5Authenticator;
import jcifs.smb.SmbFile;
public class KerberosAuthExample {
private static String NAME = "MySamAccountName";
private static String PWD = "MyPassword";
private static String URL = "smb://servername/path/" ;
private static String KDC = "dc.mydomain";
private static String REALM = "MYREALM";
public static void main(String[] args) throws LoginException {
// Nothing changes if I remove the following properties
Config.setProperty("jcifs.smb.client.capabilities",Kerb5Authenticator.CAPABILITIES);
Config.setProperty("jcifs.smb.client.flags2",Kerb5Authenticator.FLAGS2);
Config.setProperty("jcifs.smb.client.signingPreferred", "true");
try {
Subject subject = new Subject();
doLogin(subject);
SmbFile file = new SmbFile(URL, new Kerb5Authenticator(subject));
SmbFile[] files = file.listFiles();
for( int i = 0; i < files.length; i++ )
System.out.println( "-->" + files[i].getName() );
} catch (Exception e) {
e.printStackTrace();
}
}
public static void doLogin(Subject subject) throws LoginException{
System.setProperty("java.security.krb5.kdc", KDC);
System.setProperty("java.security.krb5.realm", REALM);
// System.setProperty("sun.security.krb5.debug", "true") ;
Map<String,Object> state = new HashMap<String,Object>();
state.put("javax.security.auth.login.name", NAME);
state.put("javax.security.auth.login.password", PWD.toCharArray());
Map<String,Object> option = new HashMap<String,Object>();
// option.put("debug", "true");
option.put("tryFirstPass", "true");
option.put("useTicketCache", "false");
option.put("doNotPrompt", "false");
option.put("storePass", "false");
Krb5LoginModule login = new Krb5LoginModule();
login.initialize(subject, null, state, option);
if(login.login()){
login.commit();
}
}
}
This program runs correctly, i.e., it prints the files and directories contained in the path defined in URL, but an exception is printed from SmbFile.listFiles:
GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))
at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:710)
at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
at jcifs.smb.SpnegoContext.initSecContext(SpnegoContext.java:80)
at jcifs.smb.Kerb5Authenticator.setup(Kerb5Authenticator.java:196)
at jcifs.smb.Kerb5Authenticator.access$000(Kerb5Authenticator.java:30)
at jcifs.smb.Kerb5Authenticator$1.run(Kerb5Authenticator.java:168)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:415)
at jcifs.smb.Kerb5Authenticator.sessionSetup(Kerb5Authenticator.java:166)
at jcifs.smb.SmbSession.sessionSetup(SmbSession.java:320)
at jcifs.smb.SmbSession.send(SmbSession.java:239)
at jcifs.smb.SmbTree.treeConnect(SmbTree.java:176)
at jcifs.smb.SmbTree.send(SmbTree.java:74)
at jcifs.smb.SmbTransport.getDfsReferrals(SmbTransport.java:771)
at jcifs.smb.Dfs.getTrustedDomains(Dfs.java:85)
at jcifs.smb.Dfs.resolve(Dfs.java:220)
at jcifs.smb.SmbFile.doConnect(SmbFile.java:916)
at jcifs.smb.SmbFile.connect(SmbFile.java:974)
at <mypackage>.KerberosAuthExample.main(KerberosAuthExample.java:34)
Caused by: KrbException: Server not found in Kerberos database (7)
at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:70)
at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:192)
at sun.security.krb5.KrbTgsReq.sendAndGetCreds(KrbTgsReq.java:203)
at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:311)
at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:115)
at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:449)
at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:641)
... 19 more
Caused by: KrbException: Identifier doesn't match expected value (906)
at sun.security.krb5.internal.KDCRep.init(KDCRep.java:143)
at sun.security.krb5.internal.TGSRep.init(TGSRep.java:66)
at sun.security.krb5.internal.TGSRep.<init>(TGSRep.java:61)
at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:55)
... 25 more
The exception is printed three times, then the list of files is correctly printed.
I found many pages with the error "Server not found in Kerberos database", which led me to double check DNS lookups and always use fully qualified names; anyway, in all the cases I could find the connection failed, while in my case it works, it's just very very noisy.
When I enable debugging, I get a lot of information, the most relevant appears to be the KRBError:
>>>KRBError:
sTime is Fri Oct 28 11:00:51 CEST 2016 1477645251000
suSec is 237586
error code is 7
error Message is Server not found in Kerberos database
realm is <MYREALM>
sname is cifs/<domainname>
msgType is 30
We don't have a test Active Directory domain, so I am using our production domain, and I don't have much control over it. Any idea to avoid all this noise?

Cannot load connection class because of underlying exception: 'java.lang.NumberFormatException: For input string: "OPENSHIFT_MYSQL_DB_PORT"'

I am trying to deploy my Jersey project on openshift. I have implemented this apple class to test the error in the another class since I guess the problem is with the establishing the database connection. in the Tails log I found this error:
Connecting to database…
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Cannot load connection class because of underlying exception: 'java.lang.NumberFormatException: For input string: "OPENSHIFT_MYSQL_DB_PORT"'.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
package org.busTracker.serverSide;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
#Path("myresource")
public class Apple {
//I modified my credients.
String host = "jdbc:mysql://$OPENSHIFT_MYSQL_DB_HOST:OPENSHIFT_MYSQL_DB_PORT/serverside";
String user = "adminBjv5a4k";
String password = "7tvPb1Bx3v8j";
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getIt() {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("Connecting to database…");
conn = DriverManager.getConnection(host,user,password);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// ignore
}
}
}
return "Hello, from apple class 14.05.15 11:35!";
}
}
Edit: I added the following to the try block after DriverManager.getConnection():
Map<String, String> env = System.getenv();
for (String envName : env.keySet()) {
System.out.format("%s=%s%n",
envName,
env.get(envName));
}
I have tried the following but I am still getting the same error:
This solution: https://forums.openshift.com/mysql-51-jboss-app-numberformatexception-mysql-url And add the following jdbc:mysql://${env.OPENSHIFT_MYSQL_DB_HOST}:${env.OPENSHIFT_MYSQL_DB_PORT}/serv‌​erside but nothing changed.
"jdbc:mysql://127.10.310.130:3306 /serverside"; This values are from the phpmyadmin of the app.
the problem is because of this line
String host = "jdbc:mysql://$OPENSHIFT_MYSQL_DB_HOST:OPENSHIFT_MYSQL_DB_PORT/serverside";
to get the environment variable, you need to use the method System.getEnv().get("[the variable name]"). So, in your case, the host variable should looks like this
String host = "jdbc:mysql://"
+ System.getenv().get("OPENSHIFT_MYSQL_DB_HOST")
+ ":"
+ System.getenv().get("OPENSHIFT_MYSQL_DB_PORT")
+ "/serverside";
by the way, your edit does not work because the application already throws an exception before it execute the code. so, to make it work, you need to put it before the DriverManager.getConnection() function.
You could replace those variables as below .
<property name="url"
value="jdbc:mysql://$OPENSHIFT_MYSQL_DB_HOST:$OPENSHIFT_MYSQL_DB_PORT/
yourdatabasename" />
can be replaced as below.
<property name="url"
value="jdbc:mysql://127.12.97.2:3306/yourdatabasename"
/>
jdbc:mysql://127.12.97.2:3306/yourdatabasename"The IP address and the portnumber can be obtained from the openshift phpmyadmin page and they are usually displayed on top of the admin page.
I tried all the above solutions but it didn't solve my problem. So anyone still getting that exception, try this.
The value stored in environment variable $OPENSHIFT_MYSQL_DB_HOST is something like
'jdbc:mysql://adminuname:adminpass#127.02.0.1:3306/appname'
. Therefore, using that value to create the url for DriverManager.getConnection() gives us the exception.
Instead try to know the value stored in $OPENSHIFT_MYSQL_DB_HOST and then hard code the url into a String variable without that username and password. Something like this
'jdbc:mysql://127.02.0.1:3306/appname'
For me it started working after making this modification. All other environment variables can be used as it is.
I found this solution here.

Cloudant AuthCookie may not be null

I am currently trying to add entries into Cloudant using this link:
https://github.com/cloudant/java-cloudant#installation-and-usage
Below is my code
package sample;
import java.util.List;
import com.cloudant.client.api.CloudantClient;
public class Cloudant {
public static void main (String[] args){
String password = System.getProperty("gffgasdas");
CloudantClient client = new CloudantClient("wiz.cloudant.com",password);
System.out.println("Connected to Cloudant");
System.out.println("Server Version: " + client.serverVersion());
List<String> databases = client.getAllDbs();
System.out.println("All my databases : ");
for ( String db : databases ) {
System.out.println(db);
}
}
}
I am getting this error:
Exception in thread "main" java.lang.IllegalArgumentException: AuthCookie may not be null.
at org.lightcouch.internal.CouchDbUtil.assertNotEmpty(Unknown Source)
at com.cloudant.client.api.CloudantClient.<init>(Unknown Source)
at sample.Cloudant.main(Cloudant.java:11)
I have all the necessary important imports. Any help would be appreciated thanks.
I'm not sure you're using the right constructor. It looks like you need to use the three-argument constructor CloudantClient(cloudantAccountName, username, password).
Your line:
CloudantClient client = new CloudantClient("wiz.cloudant.com",password);
Needs to be:
CloudantClient client = new CloudantClient("wiz", "wiz", password);
The two-argument version assumes you are passing a cookie rather than a password.

Registering and using a custom java.net.URL protocol

I was trying to invoke a custom url from my java program, hence I used something like this:
URL myURL;
try {
myURL = new URL("CustomURI:");
URLConnection myURLConnection = myURL.openConnection();
myURLConnection.connect();
} catch (Exception e) {
e.printStackTrace();
}
I got the below exception:
java.net.MalformedURLException: unknown protocol: CustomURI
at java.net.URL.(Unknown Source)
at java.net.URL.(Unknown Source)
at java.net.URL.(Unknown Source)
at com.demo.TestDemo.main(TestDemo.java:14)
If I trigger the URI from a browser then it works as expected but if I try to invoke it from the Java Program then I am getting the above exception.
EDIT:
Below are the steps I tried (I am missing something for sure, please let me know on that):
Step 1: Adding the Custom URI in java.protocol.handler.pkgs
Step 2: Triggering the Custom URI from URL
Code:
public class CustomURI {
public static void main(String[] args) {
try {
add("CustomURI:");
URL uri = new URL("CustomURI:");
URLConnection uc = uri.openConnection();
uc.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void add( String handlerPackage ){
final String key = "java.protocol.handler.pkgs";
String newValue = handlerPackage;
if ( System.getProperty( key ) != null )
{
final String previousValue = System.getProperty( key );
newValue += "|" + previousValue;
}
System.setProperty( key, newValue );
System.out.println(System.getProperty("java.protocol.handler.pkgs"));
}
}
When I run this code, I am getting the CustomURI: printed in my console (from the add method) but then I am getting this exception when the URL is initialized with CustomURI: as a constructor:
Exception in thread "main" java.lang.StackOverflowError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at java.net.URL.getURLStreamHandler(Unknown Source)
at java.net.URL.<init>(Unknown Source)
at java.net.URL.<init>(Unknown Source)
at sun.misc.URLClassPath$FileLoader.getResource(Unknown Source)
at sun.misc.URLClassPath.getResource(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.net.URL.getURLStreamHandler(Unknown Source)
at java.net.URL.<init>(Unknown Source)
at java.net.URL.<init>(Unknown Source)
Please advice how to make this work.
Create a custom URLConnection implementation which performs the job in connect() method.
public class CustomURLConnection extends URLConnection {
protected CustomURLConnection(URL url) {
super(url);
}
#Override
public void connect() throws IOException {
// Do your job here. As of now it merely prints "Connected!".
System.out.println("Connected!");
}
}
Don't forget to override and implement other methods like getInputStream() accordingly. More detail on that cannot be given as this information is missing in the question.
Create a custom URLStreamHandler implementation which returns it in openConnection().
public class CustomURLStreamHandler extends URLStreamHandler {
#Override
protected URLConnection openConnection(URL url) throws IOException {
return new CustomURLConnection(url);
}
}
Don't forget to override and implement other methods if necessary.
Create a custom URLStreamHandlerFactory which creates and returns it based on the protocol.
public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
#Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("customuri".equals(protocol)) {
return new CustomURLStreamHandler();
}
return null;
}
}
Note that protocols are always lowercase.
Finally register it during application's startup via URL#setURLStreamHandlerFactory()
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
Note that the Javadoc explicitly says that you can set it at most once. So if you intend to support multiple custom protocols in the same application, you'd need to generify the custom URLStreamHandlerFactory implementation to cover them all inside the createURLStreamHandler() method.
Alternatively, if you dislike the Law of Demeter, throw it all together in anonymous classes for code minification:
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
public URLStreamHandler createURLStreamHandler(String protocol) {
return "customuri".equals(protocol) ? new URLStreamHandler() {
protected URLConnection openConnection(URL url) throws IOException {
return new URLConnection(url) {
public void connect() throws IOException {
System.out.println("Connected!");
}
};
}
} : null;
}
});
If you're on Java 8 already, replace the URLStreamHandlerFactory functional interface by a lambda for further minification:
URL.setURLStreamHandlerFactory(protocol -> "customuri".equals(protocol) ? new URLStreamHandler() {
protected URLConnection openConnection(URL url) throws IOException {
return new URLConnection(url) {
public void connect() throws IOException {
System.out.println("Connected!");
}
};
}
} : null);
Now you can use it as follows:
URLConnection connection = new URL("CustomURI:blabla").openConnection();
connection.connect();
// ...
Or with lowercased protocol as per the spec:
URLConnection connection = new URL("customuri:blabla").openConnection();
connection.connect();
// ...
If you don't want to take over the one-and-only URLStreamHandlerFactory, you can actually use a hideous, but effective naming convention to get in on the default implementation.
You must name your URLStreamHandler class Handler, and the protocol it maps to is the last segment of that class' package.
So, com.foo.myproto.Handler->myproto:urls,
provided you add your package com.foo to the list of "url stream source packages" for lookup on unknown protocol. You do this via system property "java.protocol.handler.pkgs" (which is a | delimited list of package names to search).
Here is an abstract class that performs what you need: (don't mind the missing StringTo<Out1<String>> or StringURLConnection, these do what their names suggest and you can use whatever abstractions you prefer)
public abstract class AbstractURLStreamHandler extends URLStreamHandler {
protected abstract StringTo<Out1<String>> dynamicFiles();
protected static void addMyPackage(Class<? extends URLStreamHandler> handlerClass) {
// Ensure that we are registered as a url protocol handler for JavaFxCss:/path css files.
String was = System.getProperty("java.protocol.handler.pkgs", "");
String pkg = handlerClass.getPackage().getName();
int ind = pkg.lastIndexOf('.');
assert ind != -1 : "You can't add url handlers in the base package";
assert "Handler".equals(handlerClass.getSimpleName()) : "A URLStreamHandler must be in a class named Handler; not " + handlerClass.getSimpleName();
System.setProperty("java.protocol.handler.pkgs", handlerClass.getPackage().getName().substring(0, ind) +
(was.isEmpty() ? "" : "|" + was ));
}
#Override
protected URLConnection openConnection(URL u) throws IOException {
final String path = u.getPath();
final Out1<String> file = dynamicFiles().get(path);
return new StringURLConnection(u, file);
}
}
Then, here is the actual class implementing the abstract handler (for dynamic: urls:
package xapi.dev.api.dynamic;
// imports elided for brevity
public class Handler extends AbstractURLStreamHandler {
private static final StringTo<Out1<String>> dynamicFiles = X_Collect.newStringMap(Out1.class,
CollectionOptions.asConcurrent(true)
.mutable(true)
.insertionOrdered(false)
.build());
static {
addMyPackage(Handler.class);
}
#Override
protected StringTo<Out1<String>> dynamicFiles() {
return dynamicFiles;
}
public static String registerDynamicUrl(String path, Out1<String> contents) {
dynamicFiles.put(path, contents);
return path;
}
public static void clearDynamicUrl(String path) {
dynamicFiles.remove(path);
}
}
You made a recursion/endless-loop.
The Classloader searching for the class in different ways.
The stacktrace (URLClassPath) is like this:
Load a resource.
Did i load every protocol? No!
Load all protocoll-Handlers, i cant find the File «your java.protocol.handler.pkgs-package».CustomURI.Handler.
The class is a resource! Did i load every protocol? No!
Load all protocoll-Handlers, i cant find the File «your java.protocol.handler.pkgs-package».CustomURI.Handler.
The class is a resource! Did i load every protocol? No!
Load all protocoll-Handlers, i cant find the File «your java.protocol.handler.pkgs-package».CustomURI.Handler.
The class is a resource! Did i load every protocol? No!
Load all protocoll-Handlers, i cant find the File «your java.protocol.handler.pkgs-package».CustomURI.Handler.
The class is a resource! Did i load every protocol? No!
Load all protocoll-Handlers, i cant find the File «your java.protocol.handler.pkgs-package».CustomURI.Handler.
...... StackOverflowException!!!

Simple Java web service issue

I want to create a webservice in Java that accesses a database stored in an external server. I have created a BeepWebService class containing the main information:
#WebService
public class BeepWebService {
private Connection conn = null;
private String url = "jdbc:mysql://xxxxxx.ipagemysql.com/";
private String dbName = "beep";
private String userName = "beep_user_name";
private String password = "pswrd";
private String db_str = " select Name beep.SW where Name = ";
public BeepWebService(){
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
this.conn = DriverManager.getConnection(url+dbName,userName,password);
System.out.println("Connected to the database");
}catch (Exception e) {
System.out.print("failed");
}
}
#WebMethod
public String returnFormat(#WebParam(name="input_value") String input){
String str = null;
String query = db_str+input;
try {
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery(query);
while (rs.next()) {
str = rs.getString(2);
System.out.println(str);
}
rs.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
return str;
}
}
I have then created the publisher class, named BeepWebServicePublisher:
public class BeepWebServicePublisher {
public static void main(String[] args){
System.out.println("Web Service initiating...");
Endpoint.publish("http://xxxxxx.ipagemysql.com/", new BeepWebService());
}
}
Unfortunately after compiling successfully the two classes and run the application, the output message is 'failed' (meaning that the connection couldn't be estabilished with the database) followed by an exception error. This is the complete output:
Web Service starting..
failedException in thread "main" com.sun.xml.internal.ws.server.ServerRtException: Server Runtime Error: java.net.BindException: Address already in use: bind
at com.sun.xml.internal.ws.transport.http.server.ServerMgr.createContext(Unknown Source)
at com.sun.xml.internal.ws.transport.http.server.HttpEndpoint.publish(Unknown Source)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(Unknown Source)
at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(Unknown Source)
at javax.xml.ws.Endpoint.publish(Unknown Source)
at com.BeepServicePackage.server.BeepWebServicePublisher.main(BeepWebServicePublisher.java:17)
Caused by: java.net.BindException: Address already in use: bind
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(Unknown Source)
at sun.nio.ch.ServerSocketAdaptor.bind(Unknown Source)
at sun.net.httpserver.ServerImpl.<init>(Unknown Source)
at sun.net.httpserver.HttpServerImpl.<init>(Unknown Source)
at sun.net.httpserver.DefaultHttpServerProvider.createHttpServer(Unknown Source)
at com.sun.net.httpserver.HttpServer.create(Unknown Source)
... 6 more
As I am a novice in this field, can someone tell me if there is something wrong in the code or the problem may be with the server? Thanks!
Print out the entire stack trace; it'll give you more information than your "failed" message.
Where did you register the MySQL JDBC driver? I don't see it.
UPDATE: I'd recommend that you decompose the problem. Don't put the database code in the web service. Create an interface-based POJO that you can test off line. Get it working, then give an instance to the web service to use.
You have 99 problems, son. Start by fixing one at a time.
This is wrong:
private String db_str = " select Name beep.SW where Name = ";
You need a binding parameter:
private String db_str = " select Name beep.SW where Name = ?";
You need a PreparedStatement, not a Statement.
Then you want to bind the name you pass in.
You only have one column returned by the SELECT; why do you setString on column 2?
Wrong in so many ways.

Categories