I am trying to achieve the automatic update for my java web-start applicaiton. Logic: I am fetching the jnlp file from the server and comparing the timestamp with the current one. if there is difference then download the latest file and restart the application with javaws command. Now I have two problems.
1. I am not able to fetch the local jnlp file (because the location for jnlp file is different for different operating system as mentioned here
2. I am not able to find a graceful way to restart the application after killing the current running application. I would appreciate if there is any other graceful solution available. Thanks
My code:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import javax.swing.JOptionPane;
import org.apache.log4j.Logger;
import com.ibm.nzna.projects.qit.app.PropertySystem;
/**
* QitUpdater . java
*
* #Info Checks for updates for the JWS Application
*
* This program will try to use a given URL to connect online to check for
* a newer version of the jnlpFile. The program then compares the last
* modified dates of the local copy and the URL copy, and notifies the
* user if the URL copy is newer, via a Dialog box popup. The newer
* version can then, be downloaded and installed using JWS.
*
* #Warnings If the server containing QIT changes its directory or location then
* the program will error out every time since the URL link is
* hard-coded.
*
* #author Ashish Tyagi
* #version 4/22/2013
*
*/
public abstract class QitUpdater {
// constant which hold the location of property file and server location
public final static String jnlpFile = PropertySystem.getString(PropertySystem.PROPERTY_JNLP_FILE);
public final static String fileDirectoryURL = PropertySystem.getString(PropertySystem.PROPERTY_JNLP_SERVER);
static Logger logger = Logger.getLogger(QitUpdater.class.getName());
// private variables
private static HttpURLConnection huc;
private static File oldFile = null;
private static long localDate = 0;
private static long remoteDate = 0;
public static void checkUpdates(boolean displayErrors,boolean displayIsUpToDate,boolean autoRunner){
logger.info("value of jnlp file: "+fileDirectoryURL+"/"+jnlpFile);
if(jnlpFile !=null && fileDirectoryURL != null)
checkForUpdates(displayErrors, displayIsUpToDate, autoRunner);
}
/**
* Starts a new task to check for QIT updates.
*
* If there is no connection or the program is up to date, then this method
* returns normally. Otherwise, it will exit the old program and execute the
* newer QIT program.
*
* #param displayErrors
* will show all error messages in popups, if any occur. This is
* recommended to be false on boostrapping, so the 'offline user'
* is not annoyed.
*
* #param displayIsUpToDate
* will show a popup letting the user know if their current
* version of QIT is up to date, if they have the most up to date
* version. Otherwise, it will ignore the popup.
*
* #param autoRunNewer
* will automatically execute the newer JNLP file, if it is found
* or downloaded. This is recommended to be false if this method
* is being called from within a user action, like a button
* press. If it is set to false, a dialog will ask the user to
* restart QIT in order to finish updating the program, if an
* update was found.
*/
public static void checkForUpdates(boolean displayErrors,
boolean displayIsUpToDate, boolean autoRunNewer) {
// Try to find a similarly named file
// in the current local directory
oldFile = new File(jnlpFile);
if (oldFile.exists()) // find the JNLP file
{
// grab the local last modified date to compare
localDate = oldFile.lastModified();
}
// Try to access the base URL
int code = 404;
try {
URL u = new URL(fileDirectoryURL);
huc = (HttpURLConnection) u.openConnection();
huc.setRequestMethod("GET");
huc.connect();
code = huc.getResponseCode();
} catch (MalformedURLException e) {
if (displayErrors)
printError("Error: Could not check for updates.\nMalformedURLException: "
+ e.getMessage()
+ "\n\nClick OK to continue using QIT.");
return;
} catch (IOException e) {
if (displayErrors)
printError("Error: Could not check for updates.\nIOException: "
+ e.getMessage()
+ "\n\nClick OK to continue using QIT.");
return;
}
if (code == 200) {
// 200 is a valid connection
// scan URL for versions
try {
StringBuilder sb = new StringBuilder();
sb.append(fileDirectoryURL).append("/").append(jnlpFile);
URL u = new URL(sb.toString());
huc = (HttpURLConnection) u.openConnection();
huc.setRequestMethod("GET");
huc.connect();
// grab the last modified date
remoteDate = huc.getLastModified();
} catch (MalformedURLException e) {
if (displayErrors)
printError("Error: Failed to download.\n\n"
+ e.getMessage()
+ "\n\nClick OK to continue using QIT.");
return;
} catch (IOException e) {
if (displayErrors)
printError("Error: Failed to download.\n\n"
+ e.getMessage()
+ "\n\nClick OK to continue using QIT.");
return;
}
// compare last modified dates of JNLP files
if (remoteDate != localDate) {
// found a newer version of JNLP
// ask to download
if (0 == printQuestion("An updated version of QIT is available.\n\nLast updated:\n"
+ new Date(remoteDate).toString()
+ "\n\nDo you want to download and install it?")) {
// download and install
try {
downloadUrlFile(jnlpFile, fileDirectoryURL + "/"
+ jnlpFile);
oldFile.setLastModified(remoteDate);
// set the date to the date on the server
if (autoRunNewer) {
// run the JNLP file
try {
Runtime.getRuntime()
.exec("javaws "+jnlpFile);
System.exit(0);// quit this version of QIT
} catch (IOException e) {
if (displayErrors)
printError("Error:\n"
+ e.getMessage()
+ "\n\nClick OK to continue using QIT.");
}
} else
printInfo("In order to finish installing the\nupdate, QIT needs to be restarted.");
} catch (Exception e) {
if (displayErrors)
printError("Error: Failed to download " + jnlpFile
+ ".\n\n" + e.getMessage()
+ "\n\nClick OK to continue using QIT.");
}
}
} else {
// modified dates are the same
// try to launch the current JNLP
if(oldFile.exists())
{
// run the JNLP file
try {
Runtime.getRuntime()
.exec("javaws "+jnlpFile);
System.exit(0);// quit this version of QIT
} catch (IOException e) {
if (displayErrors)
printError("Error:\n"
+ e.getMessage()
+ "\n\nClick OK to continue using QIT.");
}
}
// up to date
if (displayIsUpToDate)
printInfo("QIT is up to date.\n\nLast update was:\n"
+ (new Date(localDate).toString())
+ "\n\nClick OK to continue.");
}
}
return;
}
/**
* Downloads the urlString to the filename at the current directory.
*
* #param filename
* #param urlString
* #throws MalformedURLException
* #throws IOException
*/
public static void downloadUrlFile(String filename, String urlString)
throws MalformedURLException, IOException {
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
URL url = new URL(urlString);
huc = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(url.openStream());
fout = new FileOutputStream(filename);
byte data[] = new byte[1024];
int count;
while ((count = in.read(data, 0, 1024)) != -1) {
fout.write(data, 0, count);
}
} finally {
if (in != null)
in.close();
if (fout != null)
fout.close();
}
}
/**
* Display an error
*
* #param e
*/
private static void printError(String e) {
JOptionPane.showMessageDialog(null, e, "Error",
JOptionPane.ERROR_MESSAGE);
}
/**
* Display some information
*
* #param s
*/
private static void printInfo(String s) {
JOptionPane.showMessageDialog(null, s, "Information",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Prompt a Yes/No Question
*
* #param String
* q
* #return int 0 means YES, 1 means NO, -1 means they clicked "X" close
*/
private static int printQuestion(String q) {
return JOptionPane.showConfirmDialog(null, q, "Question",
JOptionPane.YES_NO_OPTION);
}
}
I am trying to achieve the automatic update for my java web-start application
Use the DownloadService of the JNLP API.
DownloadService service allows an application to control how its own resources are cached, to determine which of its resources are currently cached, to force resources to be cached, and to remove resources from the cache. The JNLP Client is responsible for providing a specific implementation of this service.
Related
I would like to know how to properly put in a text file and then convert it to an HTML file.
When I try putting a text file I get the errors
java.security.InvalidParameterException: Configuration file unreadable.
at com.outsideinsdk.ExportTest.parseConfig(ExportTest.java:51)
at com.outsideinsdk.ExportTest.<init>(ExportTest.java:35)
at com.outsideinsdk.ExportTest.main(ExportTest.java:197)
Sample code below
package com.outsideinsdk;
import com.outsideinsdk.*;
import java.io.*;
import java.security.*;
import java.util.*;
/**
* The <code>ExportTest</code> class tests the {#link Export Export} technology
* according to the properties provided in a given configuration file. The
* configuration file is assumed to be correctly formatted.
*
* #author Kevin Glannon
* #version 1.00
* #see Export Export
*/
public class ExportTest
{
private static final String INPUTPATHKEY = "inputpath";
private static final String OUTPUTPATHKEY = "outputpath";
private static final String OUTPUTIDKEY = "outputid";
Properties configProps = new Properties();
/**
* Since <code>ExportTest</code> objects are always associated with a
* configuration file, the constructor requires a configuration file path.
*
* #param cfp The configuration file path.
*/
public ExportTest(String cfp)
throws FileNotFoundException, IOException
{
parseConfig(cfp);
}
/**
* Parse the configuration file specified by the given path.
*
* #param cfp The configuration file path.
*/
public void parseConfig(String cfp)
throws FileNotFoundException, IOException
{
// Assure the configuration file exists and is readable.
File cff = new File(cfp);
if (!cff.exists() || !cff.isFile() || !cff.canRead())
{
throw(new InvalidParameterException("Configuration file unreadable."));
}
BufferedReader cfr = new BufferedReader(new FileReader(cff));
String line;
// Loop over all lines from the file.
while ((line = cfr.readLine()) != null)
{
processLine(line);
}
}
/**
* Support the parsing of the configuration file by processing a given
* line.
*
* #param l A line from a configuration file.
*/
private void processLine(String l)
{
// Look for comments.
int indPound = l.indexOf('#');
// Remove comments and whitespace.
String line = (indPound == -1) ? l.trim() :
l.substring(0, indPound).trim();
if (line.length() != 0)
{
StringTokenizer stl = new StringTokenizer(line);
String key = stl.nextToken();
String value = stl.nextToken();
while(stl.hasMoreTokens())
{
value +=" " + stl.nextToken();
}
// Fill in the appropriate property.
configProps.setProperty(key, value);
}
}
/**
* Run the conversion using the given input path, output path.
*
* #param ifp Input path.
* #param ofp Output path.
* #param timeout Export process timeout in milliseconds.
*/
public void convert(String ifp, String ofp, long timeout)
{
String oid = configProps.getProperty(OUTPUTIDKEY);
// Display the parameters.
System.out.println("Input Path: "+ifp+" Output Path: "+ofp+
" Output ID: "+oid);
// Remove extra control properties.
configProps.remove(INPUTPATHKEY);
configProps.remove(OUTPUTPATHKEY);
// Create list of input files.
File iff = new File(ifp);
File [] iffa;
if (iff.isDirectory())
iffa = iff.listFiles();
else
{
iffa = new File[1];
iffa[0] = iff;
}
// Create output directory if needed. Assuming that if the input path
// is a directory, the output path should also be a directory.
File off = new File(ofp);
if (iff.isDirectory() && !off.exists()) off.mkdir();
// Process the conversion.
Export e = new Export(configProps);
if (off.isDirectory())
{
// The outputid is in the form fi_XXX where XXX is a reasonable
// extension so we take the extension for the oid.
// oid.substring(3) means to get the string following the fi_
String ext = "." + oid.substring(3);
for (int i=0; i<iffa.length; i++)
{
String ifn = iffa[i].toString();
String ofn = ofp + File.separator + iffa[i].getName() + ext;
System.out.println("Converting "+ifn+" to "+ofn);
ExportStatusCode result = e.convert(ifn, ofn, oid, timeout);
if (result.getCode() == ExportStatusCode.SCCERR_OK.getCode())
{
System.out.println("Conversion Successful!");
}
else {
System.out.println("Conversion Error: " + result);
}
}
}
else
{
for (int i=0; i<iffa.length; i++)
{
ExportStatusCode result = e.convert(iffa[i].toString(), ofp, oid, timeout);
if (result.getCode() == ExportStatusCode.SCCERR_OK.getCode())
{
System.out.println("Conversion Successful!");
}
else {
System.out.println("Conversion Error: " + result);
}
}
}
}
/**
* Run the test according to the given arguments. These arguments must adhere to the following usage.<br><br>
* Usage:<br>
* ExportTest InputPath OutputPath ConfigurationFile [Timeout]<br><br>
*
* InputPath and OutputPath may be single files or directories. If InputPath is a directory, then all files in
* that directory will be converted, but without recursion. If OutputPath is a directory, then all converted
* files from InputPath are placed in the OutputPath directory by appending an extension which represents the
* output file type. Timeout is in milliseconds.
*
* #param args Command line arguments.
*/
public static void main(String[] args)
{
int count = args.length;
// Check for specification of configuration file.
if (count != 3 && count != 4)
{
System.out.println("Input path, output path and configuration file are required.");
System.out.println("Usage: ExportTest InputPath OutputPath "+
"ConfigurationFile [Timeout(in milliseconds)]");
System.out.println();
}
else
{
ExportTest ct = null;
try
{
ct = new ExportTest(args[2]);
}
catch (Exception ex)
{
ex.printStackTrace();
return;
}
long timeout = 0;
if( count == 4 )
{
timeout = Integer.decode( args[3] ).longValue();
}
ct.convert(args[0], args[1], timeout);
}
}
}
This is how my program arguments look like: here
This is where the yes.txt files are located in the project called explorer: here
I tried installing tinyb from the repository: https://github.com/intel-iot-devkit/tinyb
I've build the tinyb.jar and add it to the IntellJ project as a library.
I ran the sample code provided in tinyb examples with small modification(commented out some code in the main method before the Bluetooth Manager initialization):
import tinyb.*;
import java.util.*;
import java.util.concurrent.locks.*;
import java.util.concurrent.TimeUnit;
public class HelloTinyB {
private static final float SCALE_LSB = 0.03125f;
static boolean running = true;
static void printDevice(BluetoothDevice device) {
System.out.print("Address = " + device.getAddress());
System.out.print(" Name = " + device.getName());
System.out.print(" Connected = " + device.getConnected());
System.out.println();
}
static float convertCelsius(int raw) {
return raw / 128f;
}
/*
* After discovery is started, new devices will be detected. We can get a list of all devices through the manager's
* getDevices method. We can the look through the list of devices to find the device with the MAC which we provided
* as a parameter. We continue looking until we find it, or we try 15 times (1 minutes).
*/
static BluetoothDevice getDevice(String address) throws InterruptedException {
BluetoothManager manager = BluetoothManager.getBluetoothManager();
BluetoothDevice sensor = null;
for (int i = 0; (i < 15) && running; ++i) {
List<BluetoothDevice> list = manager.getDevices();
if (list == null)
return null;
for (BluetoothDevice device : list) {
printDevice(device);
/*
* Here we check if the address matches.
*/
if (device.getAddress().equals(address))
sensor = device;
}
if (sensor != null) {
return sensor;
}
Thread.sleep(4000);
}
return null;
}
/*
* Our device should expose a temperature service, which has a UUID we can find out from the data sheet. The service
* description of the SensorTag can be found here:
* http://processors.wiki.ti.com/images/a/a8/BLE_SensorTag_GATT_Server.pdf. The service we are looking for has the
* short UUID AA00 which we insert into the TI Base UUID: f000XXXX-0451-4000-b000-000000000000
*/
static BluetoothGattService getService(BluetoothDevice device, String UUID) throws InterruptedException {
System.out.println("Services exposed by device:");
BluetoothGattService tempService = null;
List<BluetoothGattService> bluetoothServices = null;
do {
bluetoothServices = device.getServices();
if (bluetoothServices == null)
return null;
for (BluetoothGattService service : bluetoothServices) {
System.out.println("UUID: " + service.getUUID());
if (service.getUUID().equals(UUID))
tempService = service;
}
Thread.sleep(4000);
} while (bluetoothServices.isEmpty() && running);
return tempService;
}
static BluetoothGattCharacteristic getCharacteristic(BluetoothGattService service, String UUID) {
List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
if (characteristics == null)
return null;
for (BluetoothGattCharacteristic characteristic : characteristics) {
if (characteristic.getUUID().equals(UUID))
return characteristic;
}
return null;
}
/*
* This program connects to a TI SensorTag 2.0 and reads the temperature characteristic exposed by the device over
* Bluetooth Low Energy. The parameter provided to the program should be the MAC address of the device.
*
* A wiki describing the sensor is found here: http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide
*
* The API used in this example is based on TinyB v0.3, which only supports polling, but v0.4 will introduce a
* simplied API for discovering devices and services.
*/
public static void main(String[] args) throws InterruptedException {
// if (args.length < 1) {
// System.err.println("Run with <device_address> argument");
// System.exit(-1);
// }
/*
* To start looking of the device, we first must initialize the TinyB library. The way of interacting with the
* library is through the BluetoothManager. There can be only one BluetoothManager at one time, and the
* reference to it is obtained through the getBluetoothManager method.
*/
BluetoothManager manager = BluetoothManager.getBluetoothManager();
/*
* The manager will try to initialize a BluetoothAdapter if any adapter is present in the system. To initialize
* discovery we can call startDiscovery, which will put the default adapter in discovery mode.
*/
boolean discoveryStarted = manager.startDiscovery();
System.out.println("The discovery started: " + (discoveryStarted ? "true" : "false"));
BluetoothDevice sensor = getDevice(args[0]);
/*
* After we find the device we can stop looking for other devices.
*/
try {
manager.stopDiscovery();
} catch (BluetoothException e) {
System.err.println("Discovery could not be stopped.");
}
if (sensor == null) {
System.err.println("No sensor found with the provided address.");
System.exit(-1);
}
System.out.print("Found device: ");
printDevice(sensor);
if (sensor.connect())
System.out.println("Sensor with the provided address connected");
else {
System.out.println("Could not connect device.");
System.exit(-1);
}
Lock lock = new ReentrantLock();
Condition cv = lock.newCondition();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
running = false;
lock.lock();
try {
cv.signalAll();
} finally {
lock.unlock();
}
}
});
BluetoothGattService tempService = getService(sensor, "f000aa00-0451-4000-b000-000000000000");
if (tempService == null) {
System.err.println("This device does not have the temperature service we are looking for.");
sensor.disconnect();
System.exit(-1);
}
System.out.println("Found service " + tempService.getUUID());
BluetoothGattCharacteristic tempValue = getCharacteristic(tempService, "f000aa01-0451-4000-b000-000000000000");
BluetoothGattCharacteristic tempConfig = getCharacteristic(tempService, "f000aa02-0451-4000-b000-000000000000");
BluetoothGattCharacteristic tempPeriod = getCharacteristic(tempService, "f000aa03-0451-4000-b000-000000000000");
if (tempValue == null || tempConfig == null || tempPeriod == null) {
System.err.println("Could not find the correct characteristics.");
sensor.disconnect();
System.exit(-1);
}
System.out.println("Found the temperature characteristics");
/*
* Turn on the Temperature Service by writing 1 in the configuration characteristic, as mentioned in the PDF
* mentioned above. We could also modify the update interval, by writing in the period characteristic, but the
* default 1s is good enough for our purposes.
*/
byte[] config = { 0x01 };
tempConfig.writeValue(config);
/*
* Each second read the value characteristic and display it in a human readable format.
*/
while (running) {
byte[] tempRaw = tempValue.readValue();
System.out.print("Temp raw = {");
for (byte b : tempRaw) {
System.out.print(String.format("%02x,", b));
}
System.out.print("}");
/*
* The temperature service returns the data in an encoded format which can be found in the wiki. Convert the
* raw temperature format to celsius and print it. Conversion for object temperature depends on ambient
* according to wiki, but assume result is good enough for our purposes without conversion.
*/
int objectTempRaw = (tempRaw[0] & 0xff) | (tempRaw[1] << 8);
int ambientTempRaw = (tempRaw[2] & 0xff) | (tempRaw[3] << 8);
float objectTempCelsius = convertCelsius(objectTempRaw);
float ambientTempCelsius = convertCelsius(ambientTempRaw);
System.out.println(
String.format(" Temp: Object = %fC, Ambient = %fC", objectTempCelsius, ambientTempCelsius));
lock.lock();
try {
cv.await(1, TimeUnit.SECONDS);
} finally {
lock.unlock();
}
}
sensor.disconnect();
}
}
I got the following stack error when I run it (image below) :
I've tried many solution such as this fix:
https://github.com/intel-iot-devkit/tinyb/issues/75
but gave me the same error.
Any tips and tricks appreciated Thanks.
I figured it out, for tinyb to work properly it need library files generated from the build. For me it was in /home/user/Desktop/tinyb-master/src where those files are in the folder (libtinyb.so, libtinyb.so.0, libtinyb.so.0.5.0) and also in :/home/user/Desktop/tinyb-master/java/jni where those files are in the folder (libjavatiny.so, libjavatinyb.so.0, libjavatinyb.so.0.5.0).These two path must be added in the VM Option as follow:
-Djava.library.path=/home/user/Desktop/tinyb-master/java/jni:/home/user/Desktop/tinyb-master/src and also don't forget the tinyb.jar (../tinyb-master/java/tinyb.jar) that need to be added in the java project.
I have tried a program which download files parallely using java.nio by creating a thread per file download.
package com.java.tftp.nio;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* This class is used to download files concurrently from tftp server by
* configuring the filenames, no of files.
*
* #author SHRIRAM
*
*/
public class TFTP_NIO_Client {
/**
* destination folder
* */
private String destinationFolder;
/**
* list of files names to download
* */
private List<String> fileNames;
/**
* integer indicates the number of files to download concurrently
* */
private int noOfFilesToDownload;
public TFTP_NIO_Client(List<String> fileNames, String destinationFolder,
int noOfFilesToDownload) {
this.destinationFolder = destinationFolder;
this.fileNames = fileNames;
this.noOfFilesToDownload = noOfFilesToDownload;
initializeHandlers();
}
/**
* This method creates threads to register the channel to process download
* files concurrently.
*
* #param noOfFilesToDownload
* - no of files to download
*/
private void initializeHandlers() {
for (int i = 0; i < noOfFilesToDownload; i++) {
try {
Selector aSelector = Selector.open();
SelectorHandler theSelectionHandler = new SelectorHandler(
aSelector, fileNames.get(i));
theSelectionHandler.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Setup RRQ/WRQ packet Packet : | Opcode | FileName | 0 | mode | 0 |
* Filename -> Filename in array of bytes. 0 -> indicates end of file mode
* -> string in byte array 'netascii' or 'octet'
*
* #param aOpcode
* #param aMode
* #param aFileName
* #throws IOException
*/
private void sendRequest(int aOpcode, int aMode, String aFileName,
DatagramChannel aChannel, InetSocketAddress aAddress)
throws IOException {
// Read request packet
TFTPReadRequestPacket theRequestPacket = new TFTPReadRequestPacket();
aChannel.send(
theRequestPacket.constructReadRequestPacket(aFileName, aMode),
aAddress);
}
/**
* sends TFTP ACK Packet Packet : | opcode | Block# | opcode -> 4 -> 2 bytes
* Block -> block number -> 2bytes
*
* #param aBlock
*/
private ByteBuffer sendAckPacket(int aBlockNumber) {
// acknowledge packet
TFTPAckPacket theAckPacket = new TFTPAckPacket();
return theAckPacket.getTFTPAckPacket(aBlockNumber);
}
/**
* This class is used to handle concurrent downloads from the server.
*
* */
public class SelectorHandler extends Thread {
private Selector selector;
private String fileName;
/**
* flag to indicate the file completion.
* */
private boolean isFileReadFinished = false;
public SelectorHandler(Selector aSelector, String aFileName)
throws IOException {
this.selector = aSelector;
this.fileName = aFileName;
registerChannel();
}
private void registerChannel() throws IOException {
DatagramChannel theChannel = DatagramChannel.open();
theChannel.configureBlocking(false);
selector.wakeup();
theChannel.register(selector, SelectionKey.OP_READ);
sendRequest(Constants.OP_READ, Constants.ASCII_MODE, fileName,
theChannel, new InetSocketAddress(Constants.HOST,
Constants.TFTP_PORT));
}
#Override
public void run() {
process();
}
private void process() {
System.out.println("Download started for " + fileName + " ");
File theFile = new File(destinationFolder
+ fileName.substring(fileName.lastIndexOf("/")));
FileOutputStream theFout = null;
try {
theFout = new FileOutputStream(theFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (!isFileReadFinished) {
try {
if (selector.select() == 0) {
try {
// sleep 2sec was introduced because selector is
// thread safe but keys are not thread safe
Thread.sleep(2000);
} catch (InterruptedException e) {
continue;
}
continue;
}
Set<SelectionKey> theSet = selector.selectedKeys();
Iterator<SelectionKey> theSelectedKeys = theSet.iterator();
synchronized (theSelectedKeys) {
while (theSelectedKeys.hasNext()) {
SelectionKey theKey = theSelectedKeys.next();
theSelectedKeys.remove();
if (theKey.isReadable()) {
isFileReadFinished = read(theKey, theFout,
fileName);
if (!isFileReadFinished) {
theKey.interestOps(SelectionKey.OP_READ);
}
} else if (theKey.isWritable()) {
// there is no implementation for file write to
// server.
theKey.interestOps(SelectionKey.OP_READ);
}
}
}
} catch (IOException ie) {
ie.printStackTrace();
}
}
System.out.println("Download finished for " + fileName);
try {
if (selector.isOpen()) {
selector.close();
}
if (theFout != null) {
theFout.close();
}
} catch (IOException ie) {
}
}
}
/**
* #param aKey
* registered key for the selector
* #param aOutStream
* - file output stream to write the file contents.
* #return boolean
* #throws IOException
*/
private boolean read(SelectionKey aKey, OutputStream aOutStream,
String aFileName) throws IOException {
DatagramChannel theChannel = (DatagramChannel) aKey.channel();
// data packet
TFTPDataPacket theDataPacket = new TFTPDataPacket();
ByteBuffer theReceivedBuffer = theDataPacket.constructTFTPDataPacket();
SocketAddress theSocketAddress = theChannel.receive(theReceivedBuffer);
theReceivedBuffer.flip();
byte[] theBuffer = theReceivedBuffer.array();
byte[] theDataBuffer = theDataPacket.getDataBlock();
if (theDataPacket.getOpCode() == Constants.OP_DATA) {
int theLimit = theDataPacket.getLimit();
// checks the limit of the buffer because a packet with data less
// than 512 bytes of content signals that it is the last packet in
// transmission for this particular file
if (theLimit != Constants.MAX_BUFFER_SIZE
&& theLimit < Constants.MAX_BUFFER_SIZE) {
byte[] theLastBlock = new byte[theLimit];
System.arraycopy(theBuffer, 0, theLastBlock, 0, theLimit);
// writes the lastblock
aOutStream.write(theLastBlock);
// sends an acknowledgment to the server using TFTP packet
// block number
theChannel
.send(sendAckPacket((((theBuffer[2] & 0xff) << 8) | (theBuffer[3] & 0xff))),
theSocketAddress);
if (theChannel.isOpen()) {
theChannel.close();
}
return true;
} else {
aOutStream.write(theDataBuffer);
// sends an acknowledgment to the server using TFTP packet
// block number
theChannel
.send(sendAckPacket((((theBuffer[2] & 0xff) << 8) | (theBuffer[3] & 0xff))),
theSocketAddress);
return false;
}
} else if (Integer.valueOf(theBuffer[1]) == Constants.OP_ERROR) {
System.out.println("File : " + aFileName + " not found ");
handleError(theReceivedBuffer);
}
return false;
}
/**
* This method handles the error packet received from Server.
*
* #param aBuffer
*/
private void handleError(ByteBuffer aBuffer) {
// Error packet
new TFTPErrorPacket(aBuffer);
}
}
Is it possible to download multiple files in parallel using java.nio by not creating a thread per file download? If yes can anybody suggest a solution to proceed further.
I would provide an approach to achieve what you are aiming for :
Let L the list of files to be downloaded.
Create a Map M which will hold the mapping of File name to be downloaded and the corresponding Selector instance.
For each file F in L
Get Selector SK from M corresponding to F
Process the state of the Selector by checking for any of the events being ready.
If processing is complete then set the Selector corresponding to F as null. This will help in identifying files
whose
processing is completed.Alternatively, you can remove F from
L; so that the next time you are looping you only process files that are not yet completely downloaded.
The above being said, I am curious to understand why you would want to attempt such a feat? If the thought process behind this requirement is to reduce the number of threads to 1 then it is not correct. Remember, you would end up really taxing the single thread running and for sure your throughput would not necessarily be optimal since the single thread would be dealing with both network as well as disk I/O. Also, consider the case of encountering an exception while writing one of the several files to the disk - you would end up aborting the transfer for all the files; something I am sure you do not want.
A better and more scalable approach would be to poll selectors on a single thread, but hand off any I/O activity to a worker thread. A better approach still would be to read the techniques presented in Doug Lea's paper and implement them. In fact Netty library already implements this pattern and is widely used in production.
I am a newbie in Java but I need to make a scanner (that has a built in ocr) output some content to a browser. I haven't gotten to the browser yet, but the code works when I run it as an application.
With the scanner, I received Java code that makes the scanner take a picture, then read from it and output it back to the console. I added a few lines to make it an applet:
import gx.*;
import pr.*;
import java.applet.*;
public class DocScan extends Applet
{
/**
*
*/
private static final long serialVersionUID = 1L;
static
{
try
{
System.loadLibrary("jgx");
System.loadLibrary("jpr");
}
catch (UnsatisfiedLinkError e)
{
System.err.println("Native code library failed to load." + e);
System.exit(1);
}
}
public static void main(String argv[])
{
Lib lib = new Lib();
String text;
String[] ec ={ "Ok", "Warning", "Error" };
try
{
/* Opening the PR system */
lib.FunctionStart("Opening system files");
PassportReader pr = new PassportReader(); /* Object for the PR system */
lib.FunctionEnd();
/* Validity check */
if (!pr.IsValid())
{
lib.Error("Failed to initialize!");
lib.PrintStat();
}
/* Connecting to the first device */
lib.FunctionStart("Connecting to the first device");
pr.UseDevice(0, jpr.PR_UMODE_FULL_CONTROL);
lib.FunctionEnd();
/* Using the device */
while (!lib.KbHit())
{
lib.ProcessStart("Processing document");
try
{
/* Capturing images */
lib.FunctionStart("Capturing images");
pr.Capture();
lib.FunctionEnd();
/* Getting document data */
lib.FunctionStart("Recognizing.");
prDoc doc = pr.Recognize(0);
lib.FunctionEnd();
if (!doc.IsValid()) lib.WriteLine("No data found.");
else
{
/* Displaying document type */
lib.WriteLine("Document type: " + doc.Code() + ", status: " + ec[doc.Status() / 100]);
/* Get some fixed fields and displaying them */
text = doc.Field(jpr.PR_DF_NAME);
if (!text.equals("")) lib.WriteLine("NAME \"" + text + "\" [" + ec[doc.FieldStatus(jpr.PR_DF_NAME) / 100] + "]");
text = doc.Field(jpr.PR_DF_DOCUMENT_NUMBER);
if (!text.equals("")) lib.WriteLine("DOCUMENT NUMBER \"" + text + "\" [" + ec[doc.FieldStatus(jpr.PR_DF_DOCUMENT_NUMBER) / 100] + "]");
text = doc.Field(jpr.PR_DF_EXPIRY_DATE);
if (!text.equals("")) lib.WriteLine("EXPIRY DATE \"" + text + "\" [" + ec[doc.FieldStatus(jpr.PR_DF_EXPIRY_DATE) / 100] + "]");
/* Searching for fields and displaying them */
gxVariant pdoc = doc.ToVariant();
gxVariant fieldlist = new gxVariant();
pdoc.GetChild(fieldlist, jgx.GX_VARIANT_BY_ID, jpr.PRV_FIELDLIST, 0);
int nitems = fieldlist.GetNItems();
for (int i = 0; i < nitems; i++)
{
gxVariant field = new gxVariant();
fieldlist.GetItem(field, jgx.GX_VARIANT_BY_INDEX, 0, i);
int field_code = field.GetInt();
text = doc.Field(field_code);
if (!text.equals("")) lib.WriteLine("[" + field_code + "] \"" + text + "\" [" + ec[doc.FieldStatus(field_code) / 100] + "]");
if (field_code >= jpr.PR_DF_FORMATTED) continue;
try
{
gxImage img = doc.FieldImage(field_code);
if (img.IsValid()) img.Save(field_code + ".jpg", jgx.GX_JPEG);
}
catch (RuntimeException e)
{
lib.DisplExcp(e);
}
}
}
}
catch (RuntimeException e)
{
lib.DisplExcp(e);
}
lib.ProcessEnd();
lib.WaitForSec(3);
}
/* Closing the device */
lib.FunctionStart("Closing the device");
pr.CloseDevice();
lib.FunctionEnd();
}
catch (RuntimeException e)
{
lib.DisplExcp(e);
}
lib.PrintStat();
}
}
I am using Eclipse as an IDE. Right now my goal is to simply make the scanner "flash". I know that the output is to the console and I will not see anything from it in an applet, but it should still flash.
When I run this code as an application, it works. The scanner takes a picture and then it outputs what it has read to the console.
When I run this code as an Applet, the applet starts and does nothing. It just stays there with no errors of any kind (at least that's what Eclipse is showing me).
I read that I should allow the applet accesss, so I edited:
c:\program files\java\jre8\lib\security\java.policy
and added this at the end:
grant {
permission java.security.AllPermission;
};
Which should allow applets full access. However, there is no change - the applet still launches and does nothing.
Can anyone point me in the right direction? Why is the code not working when I run it as an applet?
I was writing a java tool that toggles wether a game mod is active (specifically, the game is Dwarf Fortress, and the mod is DFHack) and the program is nearly done. However, I cant seem to get the variables right that tell the program how to check if the mod is active or not.
I got this status file containing a single character, being 1 for active and 0 for inactive.
This is the code (By the way, if it is needed: I checked the name of the file and it matches the class declaration).
package nl.dirkkok.dfhacktoggle;
/*
* DFHacktoggle
* 28-12-2013 # 2:02 PM
*
* This program will disable DFHack if it is enabled, and enable it if it is disabled.
*
* Using this tool is at your own risk. If you send me an email complaining about this program doing anything you dont want, then I will laugh at you, and tell you that you cant read. :)
*
* Created by Dirk Kok <d.kok.2000#gmail.com>. This tool is my property, but I do not claim rights of neither Dwarf Fortress nor DFHack.
*/
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.IOException;
import java.nio.file.NoSuchFileException;
public class Dfhacktoggle {
private static Path statusfile = "dfhack-status";
private boolean dfhack = false;
private byte[] fileArray = new byte[1];
private byte[] active = new byte[1];
private byte[] inactive = new byte[1];
private file dfhacksdl = "SDLdfhack.dll";
private file vanillasdl = "SDLreal.dll";
private file sdl = "SDL.dll";
active[] <byte> = 1;
inactive[] <byte> = 0;
public static void main(String[] args) {
try {
fileArray = Files.readAllBytes(file);
if (fileArray[0] == 1) {
p("DFHack is active. Deactivating...");
try {
if (vanillasdl.exists()) throw new java.io.IOException("File exists");
sdl.renameTo(dfhacksdl);
vanillasdl.renameTo(sdl);
Files.write(statusfile, inactive, WRITE);
} catch (IOException x) {
errp("DFHack could not be deactivated. Reinstalling the program will solve this.");
errp("Detailed info:");
errp("IOException: " + x);
} catch (NoSuchFileException x) {
errp("Status file could not be found. Reinstalling the program will solve this.");
errp("Detailed info:");
errp("NoSuchFileException: " + x);
}
} else if (fileArray[0] == 0) {
p("DFHack is inactive. Activating...");
try {
if(vanillasdl.exists()) throw new java.io.IOException("File exists");
sdl.renameTo(vanillasdl);
dfhacksdl.renameTo(sdl);
Files.write(statusfile, active, WRITE);
} catch (IOException x) {
errp("Status could not be checked. Reinstalling the program will solve this.");
errp("Detailed info:");
errp("IOException: " + x);
} catch (NoSuchFileException x) {
errp("Status file could not be found. Reinstalling the program will solve this.");
errp("Detailed info:");
errp("NoSuchFileException: " + x);
}
} else {
errp("DFHack's status could not be checked. Reinstalling the program will solve this.");
}
} catch (IOException x) {
errp("Status could not be checked. Reinstalling the program will solve this.");
errp("Detailed info:");
errp(x);
}
}
public void p(String txt) {
System.out.println(txt);
}
public void errp(String txt) {
System.err.println(txt);
}
}
The compiler returns this:
F:\Dfhack-swap>javac Dfhacktoggle.java
Dfhacktoggle:29: error: <identifier> expected
active[] <byte> = 1;
^
Dfhacktoggle:30: error: <identifier> expected
inactive[] <byte> = 0;
^
Your syntax is wrong there's no active[] <byte> = 1; in Java
If you want to assign it a value You can do it in this way
active[0] = 1;
inactive[0] = 0;
But there's no need for array to use it as a boolean you can just define it as a byte
byte active= 1;
byte inactive= 0;