I use dropbox /delta endpoint to track changes inside Dropbox.
More precisely, the following piece of code allow me to track changes in "/superfolder" recursively (I'm using here DbxClientV1):
List<String> listOfResults = new ArrayList<String>();
String path = "/superfolder";
String cursor = null;
while (true) {
DbxDelta<DbxEntry> deltaWithPathPrefix = client.getDeltaWithPathPrefix(cursor, path);
cursor = deltaWithPathPrefix.cursor;
if (deltaWithPathPrefix.reset) {
System.out.println("Reset!");
}
for (DbxDelta.Entry entry : deltaWithPathPrefix.entries) {
if (entry.metadata == null) {
System.out.println("Deleted: " + entry.lcPath);
listOfResults.add(entry.lcPath);
} else {
System.out.println("Added or modified: " + entry.lcPath);
}
}
if (!deltaWithPathPrefix.hasMore) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(MainSearchV1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Now, I've switched to DbxClientV2 client. To track changes on dropbox I use client.files.listFolder() in the following form:
TreeMap<String, Metadata> children = new TreeMap<String, Metadata>();
Files.ListFolderResult result;
String cursor = null;
while (true) {
if (cursor == null) {
result = client.files.listFolder("/superfolder");
} else {
result = client.files.listFolderContinue(cursor);
}
cursor = result.cursor;
for (Metadata md : result.entries) {
if (md instanceof DeletedMetadata) {
children.remove(md.pathLower);
System.out.println("Deleted: " + md.pathLower);
} else {
children.put(md.pathLower, md);
System.out.println("State: " + md.pathLower);
System.out.println(md.toString());
}
}
if (!result.hasMore) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
}
Regretably, I've discovered that I can only track changes only of "superfolder" folder.
Is there a way to get a "global cursor" that tracks changes recursively in Dropbox API v2?
The Java SDK uses the builder pattern for pretty much all calls with multiple optional arguments. If I understand your question correctly, I think you're looking for this:
result = client.files.listFolderBuilder("/superfolder")
.recursive(true)
.start();
EDIT: You asked about a "global" cursor. I think you actually meant recursive, but in case you really meant global, you can pass an empty string ("") as a path to represent the root.
Related
I am trying to get a value from the first line of a csv file ( header excluded) store in Firebase Storage
Here is the code :
private String readFromCsv() {
StorageReference refCompteActifs = FirebaseStorage.getInstance().getReference().child("my_file").child("my_file.csv");
StorageReference gsReference = refCompteActifs.getStorage().getReferenceFromUrl("gs://test-8095e.appspot.com/my_file/my_filer.csv");
File localFile = null;
try {
localFile = File.createTempFile("my_file", ".csv");
} catch (IOException e) {
e.printStackTrace();
}
File finalLocalFile = localFile;
final String[] result = {null};
List<String> rows = new ArrayList<>();
gsReference.getFile(Objects.requireNonNull(localFile)).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
try {
CSVReader reader = new CSVReader(new FileReader("./data/user/0/com.example.test/cache/" + finalLocalFile.getName()), ',', '\'', 1);
String[] nextLine = null;
while ((nextLine = reader.readNext()) != null) {
System.out.println(nextLine[4] + "\n");
rows.add(nextLine[4]);
}
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < rows.size(); i++) {
result[0] = rows.get(i);
}
}
}
System.out.println(result[0] + "\n");
return result[0];
}
The console never write "System.out.println(result[0] + "\n");" result[0] is affected inside the onlistener but I can't access it outside of it.
Thank you for your Help
That is the expected behavior. The getFile API is an asynchronous operation, which means that it executes in the background while the rest of your code continues to run. Then when the operation is complete, your onSuccess is called with the result.
This is easiest to see if you add some logging:
Log.i("File", "1. Starting to load file");
gsReference.getFile(Objects.requireNonNull(localFile)).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
Log.i("File", "2. Loaded file");
}
}
Log.i("File", "3. Started to load file");
If you run this code it outputs:
Starting to load file
Started to load file
Loaded file
This is probably not what you expected, but it is working by design - and it does completely explain why your System.out.println(result[0] + "\n"); doesn't show the file contents: the file hasn't been loaded yet.
This is an incredibly common problem, as most I/O and network APIs are asynchronous these days. The solution is always the same: any code that needs the data that is asynchronously loaded has to be inside the onSuccess handler, be called from there, or otherwise synchronized.
This means for example that you can't return the value from the file, as the return runs before the load has completed, and you'll instead want to pass a callback to your readFromCsv function, very similar to the OnSuccessListener.
For more on this, I recommend reading:
getContactsFromFirebase() method return an empty list
Setting Singleton property value in Firebase Listener
more questions on losing the asynchronous value outside of a callback
Trying to use RMI and having odd issue.
The code below I have snipped the catches. There are no exceptions in them - the code progress properly until:
reportServerRemote = Activatable.register(_desc);
When I run the code below THE FIRST TIME, I get
Exception: java.rmi.activation.UnknownGroupException: group unknown
on the call: reportServerRemote = Activatable.register(_desc);
Note that I have requested and set the _groupID.
When I run it the second time, it works. I thought it might be some kind of timing issue, and have add delays and retries at various spots, but to no effect.
ActivationSystem _activationSystem = null;
try {
String _lookMeUp = "//:" + RMID_ACTIVATION_SYSTEM_PORT + "/java.rmi.activation.ActivationSystem";
_activationSystem =
(ActivationSystem) Naming.lookup(_lookMeUp);
ActivationGroup.setSystem(_activationSystem);
ActivationGroupDesc _groupDesc = new ActivationGroupDesc(null, null);
ActivationGroupID _groupID = null;
try {
_groupID = _activationSystem.registerGroup(_groupDesc);
ActivationDesc _desc = null;
try {
_desc = new ActivationDesc(_groupID, ReportServer.class.getName(),
null,
new MarshalledObject(LicenseUtil.loadSerialAndLicense()));
reportServerRemote = Activatable.register(_desc);
Exception: java.rmi.activation.UnknownGroupException: group unknown
I added a looping check after the initial registerGroup call. If it failed I tried again. It always seems to work on the 2nd try, but I left at 10 tries - just in case.
ActivationGroupID _groupID = null;
try {
_groupID = _activationSystem.registerGroup(_groupDesc);
} catch (Exception pE) {
pE.printStackTrace();
logger.error("Unable to determine groupID for group description \"" + _groupDesc + "\"", pE);
throw new Exception("Got exception while attempting to obtain group id. Exception: " + pE);
}
/*
* Sometimes it does not work the first time. Keep trying.
*/
boolean _needToRegisterGroup = true;
for ( int i = 0; _needToRegisterGroup && i< 10; i++) {
_needToRegisterGroup = false;
try {
// See if it's there
ActivationGroupDesc _t = _activationSystem.getActivationGroupDesc(_groupID);
} catch (Exception e) {
// Try again
_groupID = _activationSystem.registerGroup(_groupDesc);
// Wait a bit before checking
try {
Thread.sleep(5000);
} catch (InterruptedException pIE) {
}
_needToRegisterGroup = true;
}
}
if ( _needToRegisterGroup ) {
throw new Exception("Never able to RegisterGroup with RMID.");
}
There are a lot of concurrent mod exception questions, but I'm unable to find an answer that has helped me resolve my issue. If you find an answer that does, please supply a link instead of just down voting.
So I originally got a concurrent mod error when attempting to search through an arraylist and remove elements. For a while, I had it resolved by creating a second arraylist, adding the discovered elements to it, then using removeAll() outside the for loop. This seemed to work, but as I used the for loop to import data from multiple files I started getting concurrent modification exceptions again, but intermittently for some reason. Any help would be greatly appreciated.
Here's the specific method having the problem (as well as the other methods it calls...):
public static void removeData(ServiceRequest r) {
readData();
ArrayList<ServiceRequest> targets = new ArrayList<ServiceRequest>();
for (ServiceRequest s : serviceQueue) {
//ConcurrentModification Exception triggered on previous line
if (
s.getClient().getSms() == r.getClient().getSms() &&
s.getTech().getName().equals(r.getTech().getName()) &&
s.getDate().equals(r.getDate())) {
JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
targets.add(s);
System.out.print("targetted"); }
}
if (targets.isEmpty()) { System.out.print("*"); }
else {
System.out.print("removed");
serviceQueue.removeAll(targets);
writeData(); }
}
public static void addData(ServiceRequest r) {
readData();
removeData(r);
if (r.getClient().getStatus().equals("MEMBER") || r.getClient().getStatus().equals("ALISTER")) {
serviceQueue.add(r); }
else if (r.getClient().getStatus().equals("BANNED") || r.getClient().getStatus().equals("UNKNOWN")) {
JOptionPane.showMessageDialog(null, "New Request failed: " + r.getClient().getSms() + " is " + r.getClient().getStatus() + "!", "ERROR: " + r.getClient().getSms(), JOptionPane.WARNING_MESSAGE);
}
else {
int response = JOptionPane.showConfirmDialog(null, r.getClient().getSms() + " is " + r.getClient().getStatus() + "...", "Manually Overide?", JOptionPane.OK_CANCEL_OPTION);
if (response == JOptionPane.OK_OPTION) {
serviceQueue.add(r); }
}
writeData(); }
public static void readData() {
try {
Boolean complete = false;
FileReader reader = new FileReader(f);
ObjectInputStream in = xstream.createObjectInputStream(reader);
serviceQueue.clear();
while(complete != true) {
ServiceRequest test = (ServiceRequest)in.readObject();
if(test != null && test.getDate().isAfter(LocalDate.now().minusDays(180))) {
serviceQueue.add(test); }
else { complete = true; }
}
in.close(); }
catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
}
public static void writeData() {
if(serviceQueue.isEmpty()) { serviceQueue.add(new ServiceRequest()); }
try {
FileWriter writer = new FileWriter(f);
ObjectOutputStream out = xstream.createObjectOutputStream(writer);
for(ServiceRequest r : serviceQueue) { out.writeObject(r); }
out.writeObject(null);
out.close(); }
catch (IOException e) { e.printStackTrace(); }
}
EDIT
The changes cause the concurrent mod to trigger every time rather than intermittently, which I guess means the removal code is better but the error now triggers at it.remove();
public static void removeData(ServiceRequest r) {
readData();
for(Iterator<ServiceRequest> it = serviceQueue.iterator(); it.hasNext();) {
ServiceRequest s = it.next();
if (
s.getClient().getSms() == r.getClient().getSms() &&
s.getTech().getName().equals(r.getTech().getName()) &&
s.getDate().equals(r.getDate())) {
JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
it.remove(); //Triggers here (line 195)
System.out.print("targetted"); }
}
writeData(); }
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificatio
nException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at data.ServiceRequest.removeData(ServiceRequest.java:195)
at data.ServiceRequest.addData(ServiceRequest.java:209) <...>
EDIT
After some more searching, I've switch the for loop to:
Iterator<ServiceRequest> it = serviceQueue.iterator();
while(it.hasNext()) {
and it's back to intermittently triggering. By that I mean the first time I attempt to import data (the removeData method is being triggered from the addData method) it triggers the concurrent mod exception, but the next try it pushes past the failure and moves on to another file. I know there's a lot of these concurrent mod questions, but I'm not finding anything that helps in my situation so links to other answers are more than welcome...
This is not how to do it, to remove elements while going through a List you use an iterator. Like that :
List<ServiceRequest> targets = new ArrayList<ServiceRequest>();
for(Iterator<ServiceRequest> it = targets.iterator(); it.hasNext();) {
ServiceRequest currentServReq = it.next();
if(someCondition) {
it.remove();
}
}
And you will not get ConcurrentModificationException this way if you only have one thread.
If there is multiple threads involved in your code, you may still get ConcurrentModificationException. One way to solve this, is to use Collections.synchronizedCollection(...) on your collection (serviceQueue) and as a result you will get a synchronized collection that will not produce ConcurrentModificationException. But, you code may become very slow.
I made a wrapper ConfigurationFile class to help handle Gdx.files stuff, and it worked fine for a long time, but now it's not working, and I don't know why.
I have two of the following two methods: internal(...) and local(...). The only difference between the two is handling the load from arguments from (File folder, String name) and (String path).
-Snip Now Unnecessary Information-
UPDATE
After more configuring, I came to find out that they're not behaving the same. I have an assets/files/ folder that Gdx.files.internal(...) will access fine, but ConfigurationFile.internal(...) will access files/, and they're set up the same way. I'll give you the two pieces of code that I used for testing.
Using Gdx.files.internal(...) directly (works as expected):
FileHandle handle = Gdx.files.internal("files/virus_data");
BufferedReader reader = null;
try {
reader = new BufferedReader(handle.reader());
String c = "";
while ((c = reader.readLine()) != null) {
System.out.println(c); // prints out all 5 lines on the file.
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Using ConfigurationFile.internal(...):
// First part, calls ConfigurationFile#internal(String path)
ConfigurationFile config = ConfigurationFile.internal("files/virus_data");
// ConfigurationFile#internal(String path)
public static ConfigurationFile internal(String path) {
ConfigurationFile config = new ConfigurationFile();
// This is literally calling Gdx.files.internal("files/virus_data");
config.handle = Gdx.files.internal(path);
config.file = config.handle.file();
config.folder = config.file.getParentFile();
config.init();
return config;
}
// ConfigurationFile#init()
protected void init() {
// File not found.
// Creates a new folder as a sibling of "assets"
// Creates a new file called "virus_data"
if (!folder.exists()) folder.mkdirs();
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
} else loadFile();
}
// ConfigurationFile#loadFile()
protected void loadFile() {
BufferedReader reader = null;
try {
reader = new BufferedReader(handle.reader());
String c = "";
while ((c = reader.readLine()) != null) {
System.out.println(c);
if (!c.contains(":")) continue;
String[] values = c.split(":");
String key = values[0];
String value = values[1];
if (values.length > 2) {
for (int i = 2; i < values.length; i++) {
value += ":" + values[i];
}
}
key = key.trim();
value = value.trim();
mapValues.put(key, value);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
What I'm having trouble understanding is what's the difference between these two ways that it is causing my ConfigurationFile to create a new File in a folder that is a sibling of assets. Could someone tell me why this is happening?
My suggestion is not to use
Gdx.files.internal(folder + "/" + name);
If you have to use the File api, do it this way:
Gdx.files.internal(new File(folder, name).toString());
This way you avoid weird things that could be happening with path separators.
If Gdx maybe needs relative paths for some reason (perhaps relative to some Gdx internal home directory), you could use NIO to do something like
final Path gdxHome = Paths.get("path/to/gdx/home");
//...
File combined = new File(folder, name);
String relativePath = gdxHome.relativize(combined.toPath()).toString();
Okay, so after intense testing, I found out the problem, which I found to be ridiculous.
Since the file is Internal, that means a new File(...) reference can't be properly made to it, but instead it's an InputStream (if I'm correct), but anyways, using the method FileHandle#file() on an Internal file causes some kind of conversion for the path, so after removing anything that dealed with FileHandle#file() for an Internal file fixed it.
I am currently working on my own version of a glossary written in Java. Truthfully, this is of academic nature and I was hoping someone could point me in the first direction. Anyway, I am reading in text from a text file and putting the words and their corresponding definitions into a Map (Tree Map to be more specific). Everything works good from there. Everything is in the map as it should be.
Now I start to get to the part where I want to go into HTML and output the contents of the map. I know how to do that with iterators and that wasn't much of a problem. However, when I try to display the content mixed in with HTML I don't get all that I want. The page is ultimately supposed to look like this: http://cse.osu.edu/~weide/rsrg/sce/now/321/421/labs/lab10/glossary.html#book
And there is this particularly tricky part where if there's a term contained within a definition it should be clickable. Here is what I have so far. Again, if anyone could help me figure out why the main guts of the HTML aren't displaying I would appreciate it very much! By the way, the text file I'm getting things from is called: terms.txt, and the html file writing to is called glossary.html.
This is what I have so far:
public class Glossary {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
Map<String, String> dictionary = new TreeMap<String, String>();
File htmlFile = new File(
"/Users/myname/Documents/workspace/Lab10/src/glossary.html");
File file = new File(
"/Users/myname/Documents/workspace/Lab10/src/terms.txt");
Writer out = new OutputStreamWriter(new FileOutputStream(htmlFile));
String term = null;
String def = null;
String key = null, value = null;
String lead = null;
String multiFinalDef = null;
Set<String> checkValues = new HashSet<String>();
String leftOver = null;
boolean check = false;
Scanner input = null;
try {
input = new Scanner(file);
while (input.hasNext()) {
String keepTrack;
boolean multi = false;
String line = input.nextLine();
term = line;
def = input.nextLine();
keepTrack = def;
while (def.length() > 0 && input.hasNext()) {
def = input.nextLine();
if (def.length() > 0) {
multiFinalDef = " " + keepTrack + def;
multi = true;
}
}
if (multi) {
dictionary.put(term, multiFinalDef);
} else {
dictionary.put(term, keepTrack);
}
checkValues.add(term);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.write("<HTML>\n");
out.write("<HEAD>\n");
out.write("</HEAD>\n");
out.write("<BODY>\n");
out.write("<H1>Glossary</H1>\n");
out.write("<HR /\n");
out.write("<H2>Index</H2>\n");
out.write("<UL>\n");
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Set s = dictionary.entrySet();
Iterator iterator = s.iterator();
while (iterator.hasNext()) {
Map.Entry m = (Map.Entry) iterator.next();
// getKey is used to get key of map.
key = (String) m.getKey();
// getValue is used to get the value of the key in map.
value = (String) m.getValue();
// this is just so I know the output from the map is actually correct. And indeed it is.
System.out.println("Key:\t\t\tValue\n " + key + "\t\t\t " + value
+ "\n");
try {
out.write("<LI>" + key + "</LI>\n");
out.write("</UL>\n");
out.write("<HR />\n");
} catch (IOException e) {
e.printStackTrace();
}
}
out.write("<H2>Terms and Definitions</H2>\n");
out.write("<UL>\n" + "<P>\n");
iterator = s.iterator();
while (iterator.hasNext()) {
Map.Entry temp = (Map.Entry) iterator.next();
// getKey is used to get key of map.
String keyTwo = (String) temp.getKey();
// getValue is used to get the value of the key in map.
String valueTwo = (String) temp.getValue();
out.write("<H3><A NAME=\" " + keyTwo + "/><B><I><FONT COLOR=\"red\">"
+ keyTwo + "</FONT></I></B></LI></H3>\n");
for(String getTerm : checkValues){
if (valueTwo.contains(getTerm)) {
check = true;
int foundTermPosition = valueTwo.indexOf(getTerm);
lead = valueTwo.substring(0, foundTermPosition - 1);
//fix left over..
leftOver = valueTwo.substring(foundTermPosition, valueTwo.length());
out.write(lead);
out.write("" + keyTwo + "");
out.write(leftOver + "\n");
//out.write("</blockquote>\n");
}
}
if( check == false)
{
out.write(lead + " " + valueTwo);
}
}
//System.out.println(valueTwo + leftOver);
// used to put words defined in file mentioned in definition
// with hyperlinks to their associated locations, and output the
// definition.
out.write("</P>\n" + "</UL>\n");
out.write("</BODY>\n");
out.write("</HTML>");
out.close();
}
}
By the time your program reaches
out.write("<H2>Terms and Definitions</H2>\n");
out.write("<UL>\n" + "<P>\n");
while (iterator.hasNext()) {
...
the iterator doesn't have any more items left, as it gets exhausted on the first while loop a few lines before, while you're printing the index. To iterate through the map again, you'll need to call the iterator method again. So the block above would become:
out.write("<H2>Terms and Definitions</H2>\n");
out.write("<UL>\n" + "<P>\n");
iterator = s.iterator();
while (iterator.hasNext()) {
...
As I understand, you want to generate html documents. In my humble opinion, the best and generic approach in your case - use any of template engines. For example - Apache Velocity.
It takes a few minutes to look through this tutorial