open URL with Java in background - java

have a problem here with Java. I'm a beginner and I don't know why it's not working.
What I want:
I have an homepage, I want to change some properties of a module. Therefore I have an .php-file. Going to the URL (looks like http://subdomain.domain.de/path_to_module/file.php?property=XY&api=Z) is all I have to do. To make this faster and easier especially also for friends, I want to code a little app.
I looked up google and get so far:
public void onClick(View v) {
try {
URL url = new URL("http://subdomain.domain.de/path_to_module/file.php?
property=XY&api=Z");
HttpURLConnection connection = null ;
try {
connection = (HttpURLConnection) url.openConnection();
}
finally
{
if( connection != null )
connection.disconnect() ;
}
} catch (MalformedURLException e){
} catch (IOException e){}
}
But that isn't working. The App don't crash or anything. It looks like it works, but when you look on the website it isn't changing anything.
Go to the URL by hand is working, so this can't be the problem...
Do you have any ideas, how to solve the problem?
Please excuse bad spelling or something like that, I'm not a native speaker.

Hey #David Conrad thanks for your help.
If I get you right, the new Code should look like this:
public void onClick(View v) {
try {
URL url = new URL("http://subdomain.domain.de/path_to_module/file.php?
property=XY&api=Z");
HttpURLConnection connection = null ;
try {
connection = (HttpURLConnection) url.openConnection();
connection.connect();
}
finally
{
if( connection != null )
connection.disconnect() ;
}
} catch (MalformedURLException e){
} catch (IOException e){}
}
I tried it, but it didn't work. Did I missunderstand what you are talking about?

The URL openConnection() method doesn't make the connection:
It should be noted that a URLConnection instance does not establish the actual network connection on creation. This will happen only when calling URLConnection.connect().
You have to call URLConnection.connect() on the HttpURLConnection object it returns.
Opens a communications link to the resource referenced by this URL, if such a connection has not already been established.
The HttpURLConnection doesn't begin transferring data right away because you may want to set HTTP headers, or you may want to do a POST or a PUT instead of a GET. You may have to get the input stream, and possibly even read from it, to cause it to make a GET request from the server (if that is what you are trying to do).
InputStream is = connection.getInputStream();
is.transferTo(new ByteArrayOutputStream());
This will read all the data from the connection and write it to a buffer, which you could discard if you don't care about its contents.

Related

Mocking/Testing HTTP Get Request

I'm trying to write unit tests for my program and use mock data. I'm a little confused on how to intercept an HTTP Get request to a URL.
My program calls a URL to our API and it is returned a simple XML file. I would like the test to instead of getting the XML file from the API online to receive a predetermined XML file from me so that I can compare the output to the expected output and determine if everything is working correctly.
I was pointed to Mockito and have been seeing many different examples such as this SO post, How to use mockito for testing a REST service? but it's not becoming clear to me how to set it all up and how to mock the data (i.e., return my own xml file whenever the call to the URL is made).
The only thing I can think of is having another program made that's running locally on Tomcat and in my test pass a special URL that calls the locally running program on Tomcat and then return the xml file that I want to test with. But that just seems like overkill and I don't think that would be acceptable. Could someone please point me in the right direction.
private static InputStream getContent(String uri) {
HttpURLConnection connection = null;
try {
URL url = new URL(uri);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
return connection.getInputStream();
} catch (MalformedURLException e) {
LOGGER.error("internal error", e);
} catch (IOException e) {
LOGGER.error("internal error", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
I am using Spring Boot and other parts of the Spring Framework if that helps.
Part of the problem is that you're not breaking things down into interfaces. You need to wrap getContent into an interface and provide a concrete class implementing the interface. This concrete class will then
need to be passed into any class that uses the original getContent. (This is essentially dependency inversion.) Your code will end up looking something like this.
public interface IUrlStreamSource {
InputStream getContent(String uri)
}
public class SimpleUrlStreamSource implements IUrlStreamSource {
protected final Logger LOGGER;
public SimpleUrlStreamSource(Logger LOGGER) {
this.LOGGER = LOGGER;
}
// pulled out to allow test classes to provide
// a version that returns mock objects
protected URL stringToUrl(String uri) throws MalformedURLException {
return new URL(uri);
}
public InputStream getContent(String uri) {
HttpURLConnection connection = null;
try {
Url url = stringToUrl(uri);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
return connection.getInputStream();
} catch (MalformedURLException e) {
LOGGER.error("internal error", e);
} catch (IOException e) {
LOGGER.error("internal error", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
}
Now code that was using the static getContent should go through a IUrlStreamSource instances getContent(). You then provide to the object that you want to test a mocked IUrlStreamSource rather than a SimpleUrlStreamSource.
If you want to test SimpleUrlStreamSource (but there's not much to test), then you can create a derived class that provides an implementation of stringToUrl that returns a mock (or throws an exception).
The other answers in here advise you to refactor your code to using a sort of provider which you can replace during your tests - which is the better approach.
If that isn't a possibility for whatever reason you can install a custom URLStreamHandlerFactory that intercepts the URLs you want to "mock" and falls back to the standard implementation for URLs that shouldn't be intercepted.
Note that this is irreversible, so you can't remove the InterceptingUrlStreamHandlerFactory once it's installed - the only way to get rid of it is to restart the JVM. You could implement a flag in it to disable it and return null for all lookups - which would produce the same results.
URLInterceptionDemo.java:
public class URLInterceptionDemo {
private static final String INTERCEPT_HOST = "dummy-host.com";
public static void main(String[] args) throws IOException {
// Install our own stream handler factory
URL.setURLStreamHandlerFactory(new InterceptingUrlStreamHandlerFactory());
// Fetch an intercepted URL
printUrlContents(new URL("http://dummy-host.com/message.txt"));
// Fetch another URL that shouldn't be intercepted
printUrlContents(new URL("http://httpbin.org/user-agent"));
}
private static void printUrlContents(URL url) throws IOException {
try(InputStream stream = url.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
private static class InterceptingUrlStreamHandlerFactory implements URLStreamHandlerFactory {
#Override
public URLStreamHandler createURLStreamHandler(final String protocol) {
if("http".equalsIgnoreCase(protocol)) {
// Intercept HTTP requests
return new InterceptingHttpUrlStreamHandler();
}
return null;
}
}
private static class InterceptingHttpUrlStreamHandler extends URLStreamHandler {
#Override
protected URLConnection openConnection(final URL u) throws IOException {
if(INTERCEPT_HOST.equals(u.getHost())) {
// This URL should be intercepted, return the file from the classpath
return URLInterceptionDemo.class.getResource(u.getHost() + "/" + u.getPath()).openConnection();
}
// Fall back to the default handler, by passing the default handler here we won't end up
// in the factory again - which would trigger infinite recursion
return new URL(null, u.toString(), new sun.net.www.protocol.http.Handler()).openConnection();
}
}
}
dummy-host.com/message.txt:
Hello World!
When run, this app will output:
Hello World!
{
"user-agent": "Java/1.8.0_45"
}
It's pretty easy to change the criteria of how you decide which URLs to intercept and what you return instead.
The answer depends on what you are testing.
If you need to test the processing of the InputStream
If getContent() is called by some code that processes the data returned by the InputStream, and you want to test how the processing code handles specific sets of input, then you need to create a seam to enable testing. I would simply move getContent() into a new class, and inject that class into the class that does the processing:
public interface ContentSource {
InputStream getContent(String uri);
}
You could create a HttpContentSource that uses URL.openConnection() (or, better yet, the Apache HttpClientcode).
Then you would inject the ContentSource into the processor:
public class Processor {
private final ContentSource contentSource;
#Inject
public Processor(ContentSource contentSource) {
this.contentSource = contentSource;
}
...
}
The code in Processor could be tested with a mock ContentSource.
If you need to test the fetching of the content
If you want to make sure that getContent() works, you could create a test that starts a lightweight in-memory HTTP server that serves the expected content, and have getContent() talk to that server. That does seem overkill.
If you need to test a large subset of the system with fake data
If you want to make sure things work end to end, write an end to end system test. Since you indicated you use Spring, you can use Spring to wire together parts of the system (or to wire the entire system, but with different properties). You have two choices
Have the system test start a local HTTP server, and when you have your test create your system, configure it to talk to that server. See the answers to this question for ways to start the HTTP server.
Configure spring to use a fake implementation of ContentSource. This gets you slightly less confidence that everything works end-to-end, but it will be faster and less flaky.

Android - Unhandled java.net.MalformedURLException

I'm getting a MalformedURLException some code in my Android Studio project. My aim is to get and display an image from a web page, and the URL seems to be fine, but it's giving me this error.
I have already put the code in a try,catch, but that is still giving me the error.
Here is the code to grab the image and display it:
try
{
url = new URL(items.get(position).getLink());
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
}
catch (IOException e)
{
throw new RuntimeException("Url Exception" + e);
}
holder.itemTitle.setText(items.get(position).getTitle());;
holder.itemHolder.setBackgroundDrawable(new BitmapDrawable(bmp));
items.get(position).getLink() is meant to get the link that is being displayed in a ListView, but even something like URL url = new URL("https://www.google.com") doesn't work.
Thanks.
your url is formatted without the protocol at the beginning try
url = new URL("http://"+items.get(position).getLink());
sometimes the url string may have special characters, in which case you need to encode it properly please see this.
And also, the url you posted in the comment is not an image.
it is exception beacuse of url class
add antoher catch like
catch (MalformedURLException e) {
e.printStackTrace();
}
Just click alt+enter and then import try catch section... this helped me...

new java.io.IOException : Call requires API level 9

First, here is my code :
public static boolean loginValide(final String username, final String password) throws IOException {
final boolean valide = false;
final String postData = "somePostParameters";
URL url;
HttpsURLConnection connexion;
url = new URL("someUrl");
connexion = (HttpsURLConnection) url.openConnection();
try {
connexion.setDoOutput(true);
final DataOutputStream dos = new DataOutputStream(connexion.getOutputStream());
dos.writeBytes(postData);
dos.flush();
dos.close();
final int responseCode = connexion.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_ACCEPTED) {
// ...
}
else {
// ...
}
} catch (final IOException e) {
throw new IOException(e); /* I am retrowing an exception so the
finally block is still called */
}
finally {
connexion.disconnect(); // Close the connection
}
return valide;
}
My problem is that I was first only declaring my method throwing an IOException. But if it happens, I suppose the HttpsUrlConnection would not be disconnected.
So I thought catching the Exception, rethrowing it so when my method is called by another class I can handle a network/connection error and tell the user about it, and so the code will still run the finally block to close the connection.
First, am I right? Or is there another way to do this?
I don't care about the try{} catch{} inside the method, I just want to be sure that the connection and streams will always be closed, whether an exception is thrown or not.
The other problem is the catch{} block where I throw the exception. Eclipse tells me:
Call requires API level 9 (current min is 8): new java.io.IOException
Seriously, I can't throw an exception using an API level below 9? I hope it's a joke...
To use IOEXception with throwable you need min API 9.. check
http://developer.android.com/reference/java/io/IOException.html#IOException(java.lang.Throwable)
Code in a finally block will always be called, even if the code in the try-block throws an exception. As for the API level restriction - it's the specific IOException(Throwable) constructor that was added in API level 9.
You can change MIN api level in eclipse
If you go into your Manifest file and set
<uses-sdk android:minSdkVersion="8" /> <!--in your case -->
Then you will have changed your entire project from running 2.2.X as a minimum to 2.3.X
While you are still building your app, you can change the minimum API level at any time.

Apache FTPClient : 530 You aren't logged in

I'm using FTPClient of apache for getting size of specific file from my server. So, the error that I faced in android is 530 You aren't logged in. while my code is such below and I've tested it in pure Java. I don't know why this error occurred on Android but all things are okay in Java.
client.connect("my-server-ip");
client.login("username", "password");
client.setKeepAlive(true);
client.setFileType(FTP.BINARY_FILE_TYPE, FTP.BINARY_FILE_TYPE);
client.setFileTransferMode(FTP.BINARY_FILE_TYPE);
client.sendCommand("SIZE " + "file-path");
try {
sizeStr = client.getReplyString().trim();
this.M_fileData.M_contentLength = Long.parseLong(sizeStr.split(" ")[1]);
System.out.println(sizeStr);
} catch (NumberFormatException e) {
e.printStackTrace();
client.disconnect();
}
Java pure result is : 213 1757682, while android result is 530 You aren't logged in.
Could any one explain me how to solve this ?
Thanks in advance.
- First of all i want you to make sure you have given the android.permission.INTERNET permission.
Well for further reference, i am giving you the code that i used to Download music clip in my android application.
I have used the Apache's commons library
public void goforIt(){
FTPClient con = null;
try
{
con = new FTPClient();
con.connect("50.xx.xx.xx");
if (con.login("Adminxxxxx", "KUjWbk361wobbyl-xxxxxx"))
{
con.enterLocalPassiveMode(); // important!
con.setFileType(FTP.BINARY_FILE_TYPE);
String data = "/sdcard/vivek.m4a";
OutputStream out = new FileOutputStream(new File(data));
boolean result = con.retrieveFile("vivekm4a.m4a", out);
out.close();
if (result) Log.v("download result", "succeeded");
con.logout();
con.disconnect();
}
}
catch (Exception e)
{
Log.v("download result","failed");
e.printStackTrace();
}
}
Whenever 530 error code return it means your username or password is incorrect. And due to login failed you cant upload file.

Java's URL openStream() can it not use HTTPS?

I was tinkering on android with WMS Layers. One of the services I want to load the layer from is serving them via Https. The wms layer example i found though uses:
InputStream input = null;
try {
input = url.openStream();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
Where url is a type URL and is set to a url that uses HTTPS. This throws an error as I suspect I have to set up my certificates or something. Is there anyway to just say accept brute force this to accept the certs? I tried something similar to this in c# and was able to just basically making a call to this:
C# code to make the https work:
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AcceptAllCertifications);
...
...
public bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification,
System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
//this might be useful later too
//http://blog.jameshiggs.com/2008/05/01/c-how-to-accept-an-invalid-ssl-certificate-programmatically/
return true;
}

Categories