jTreeModel does not expand after sending over a socket connection - java

I have written a client and server application who are connected with sockets.
The server is multithreaded and can hold more than one client.
Now am i using in my client application a jTree model, and on my server i have a folder with fictitious project folders and files in it.
First this application only was client sided with a database on a server, now i want it to fully operate over a socket connection.
The only problem is that the jTree model is created on the server. So when the program starts the client asks the server to create a jTree model of the project folder the user will use in the client application with its files in it.
The Server will send a respone with a jTree model in it and the client puts this model in the jTree swing component.
The jTree is succesfully shown to the user (so the Tree model is succesfully sended over the socket connection), but when the user wants to expand the first projectfolder map: the jTree shows for example: 'testProject' as folder.
And for example the folder testProject contains some files:
testProject.exe
bin
test.java
test2.java
src
As you see in the above example the jTree should show the above tree to the user when the user double clicks on 'testProject' in the jTree.
Now my problem
I think the problem is that the server only creates the model of the first folder.
Like it only sends a model with 'projectFolder' in it.
But i want the above structure send to the user so the user can use the jTree to download the files from the server. (something i will implement later).
How can i get a full model from the server, that the jTree can show a full model to the user with the projectfolder and all his files.
To make everything a little more clear:
My code
This fragment of code i use on my client to invoke the method that created the jTree model on the server.
public ProjectTreeModel getTreeModel(String projectName) throws ClassNotFoundException {
try {
//Creating empty object to invoke te mehod on the server.
paramObject parameters = new paramObject();
parameters.string1 = projectName;
//Creating package to invoke the right method on the server.
Packet data = new Packet("treemodel.GetModel",parameters);
//sends in this case an empty object to the server and invokes the treemodel.GetModel method on the server.
oos.writeObject(data);
oos.flush();
ProjectTreeModel model = (ProjectTreeModel) ois.readObject();
return model;
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
This piece of code i use on the server to create the projectModel and send it back as object to the client to return it as a jTree model in the previous code example.
if(data.getMethod().equals("treemodel.GetModel"))
{
//in this example i don't use this object, just ignore it.
paramObject parameters = (paramObject) data.getObject();
//Extract the information from User
String projectName = parameters.string1;
ProjectTreeModel treemodel = new ProjectTreeModel();
treemodel.newRootPath(projectName);
oos.writeObject(treemodel);
output.flush();
form.sendOutput("ProjectTreeModel succesfully sended to: " + Email);
}
And at last this is how i create the TreeModel.
import java.io.File;
import java.io.Serializable;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class ProjectTreeModel implements TreeModel, Serializable
{
File f;
private static String rootPath = "src/authorsystem/Projects";
public static void newRootPath(String newRoot)
{
String desktopPath = System.getProperty("user.home") + "\\Desktop";
desktopPath.replace("\\", "/");
rootPath = desktopPath + "\\projectfolders";
}
#Override
public Object getRoot() {
//userName = LogInForm.ingelogt;
f = new File(rootPath);
return f;
}
#Override
public Object getChild(Object parent, int index) {
File pathName = (File) parent;
String[] fileNames = pathName.list();
return new File(pathName.getPath(), fileNames[index]);
}
#Override
public int getChildCount(Object parent) {
File pathName = (File) parent;
if(pathName.list() != null)
{
String[] fileNames = pathName.list();
return fileNames.length;
}
else
{
return 0;
}
}
#Override
public boolean isLeaf(Object node) {
return ((File)node).isFile();
}
#Override
public void valueForPathChanged(TreePath path, Object newValue) {
}
#Override
public int getIndexOfChild(Object parent, Object child) {
File pathName = (File) parent;
File childName = (File) child;
if(pathName.isDirectory())
{
String[] fileNames = pathName.list();
for (int i = 0; i < fileNames.length; i++) {
if(pathName.compareTo(childName) == 0)
{
return i;
}
}
}
return -1;
}
#Override
public void addTreeModelListener(TreeModelListener l) {
}
#Override
public void removeTreeModelListener(TreeModelListener l) {
}
}
I hope somebody can help me out, or just help me with ideas how to solve this problem.

Ok just to close this topic in case if someone find this.
Its really long ago i worked on this but this is how we managed it:
For the treeModel we made our custom nodes. Instead of sending a JTreeModel object trough a socket connection we only send the data that must be shown in the tree.
After the client received the data from the server we iterated trough all the data and checked if the node is a parent or child.
This can be done basically with the overrided TreeModel class code snipper above in my Question.

Related

Create file structure from strings

I am trying to create a BitBucket plugin to get the repository structure and print it out in a structured format. The plugin creates a button on the repo page and when clicked it connects with a servlet to produce an output, however I cannot get my formatting code to work.
E.g
Instead of:
Folder 1
File 1
File 2
I want it to indent children:
Folder 1
File 1
File 2
I currently have a JS file which controls the button and makes an ajax call to a Java file, and also passes the servlet URL including the parameters for the repo (Project, Repo).
In my Java file I have a doGet which gets the repo from the parameters and uses a custom contentTreeCallback() to get the files within the repo in order to print them out, using callback.getFiles(). Within this same Java file, I have defined a node class which creates a linked hash map which takes each file, splits it into components, and with a recursive loop appends children to nested lists in order to create the file structure. This should work, however my custom contentTreeCallback() gets a string rather than the file array it needs to return. I cannot figure out what changes I need to make to get this to work. I'm guessing I either adjust the callback to get the files or I move the node class functionality into the callback class. I would prefer the second option since this class already splits the string, it seems a bit redundant to do it twice.
The servlet java class:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// Get values from the URL
projectName= req.getParameter("project");
repoName = req.getParameter("repository");
repo = repositoryService.getBySlug(projectName, repoName);
// ByteArrayOutputStream out = new ByteArrayOutputStream();
MyContentTreeCallback callback = new MyContentTreeCallback();
PageRequestImpl pr = new PageRequestImpl(0, 1000);
// Get information from the defined location, store in ByteArrayOutputStream
contentService.streamDirectory(repo, "Master", "", true, callback, pr);
resp.setContentType("text/html");
resp.getWriter().print("<html><body><p>Repository: " + repo.getName() + "</p>");
Node root = new Node(null);
for(int i = 0; i < callback.getFiles().size(); i++) {
root.add(callback.getFiles().get(i));
}
root.writeTo(resp.getWriter());
resp.getWriter().print("</body></html>");
}
static final class Node {
final String name;
final Map<String, Node> children = new LinkedHashMap<>();
Node(String name) {
this.name = name;
}
void add(File file) {
Node n = this;
for(String component: file.getPath().getComponents())
n = n.children.computeIfAbsent(component, Node::new);
}
void writeTo(Appendable w) throws IOException {
if(name != null) w.append("<li><a href='/'>").append(name).append("</a></li>\n");
if(!children.isEmpty()) {
w.append("<ul>\n");
for(Node ch: children.values()) ch.writeTo(w);
w.append("</ul>\n");
}
}
}
And the custom callback class:
public class MyContentTreeCallback extends AbstractContentTreeCallback {
ArrayList<File> files = new ArrayList<File>();
ContentTreeSummary fileSummary;
public MyContentTreeCallback() {
}
#Override
public void onEnd(#Nonnull ContentTreeSummary summary) {
fileSummary = summary;
}
#Override
public void onStart(#Nonnull ContentTreeContext context) {
System.out.print("On start");
}
#Override
public boolean onTreeNode(#Nonnull ContentTreeNode node) {
String filePath = "";
if (node.getPath().getComponents().length>1) {
for(int i=0;i<node.getPath().getComponents().length;i++) {
filePath+=node.getPath().getComponents()[i]+"/";
//filePath=filePath.substring(0,filePath.length() - 1)
}
}
else {
filePath+=node.getPath().getName();
}
String lastChar = String.valueOf(filePath.charAt(filePath.length() - 1));
if(lastChar.equals("/")){ filePath=filePath.substring(0,filePath.length() -
1); }
files.add(filePath);
return true;
}
public ArrayList<File> getFiles(){
return files;
}
}
files.add(filePath); Is where the issue is in the callback class.
I'm sure it's simpler than I am making it out to be... Thanks for any help you can give

JList in UI not reflecting changes from all peer processes

I am writing a simple chat application in Java. As soon as a new user joins, the server component of my application should inform all other clients about this event.
The relevant code on the server side is as follows:
private void notifyUser() throws IOException {
String[] user = new String[onlineUsers.size()];
int i = 0;
for(Socket sock : sockets){
out.get(i).writeInt(1);
out.get(i).writeObject(onlineUsers.toArray(user));
out.get(i).flush();
}
}
The client thread is listening on the socket using the following code:
ObjectInputStream in = new ObjectInputStream(sockfd.getInputStream());
while(true) {
command = in.readInt();
switch(command) {
case 1:
String[] user = (String[])in.readObject();
System.out.println(user);
client.addOnlineUsers(user);
}
}
The addOnlineUsers(..) method consists of the following code:
public void addOnlineUsers(String[] user) {
for(String s : user){
listmodel.addElement(s);
}
}
I have instantiated the JList like so:
JList list = new JList(listmodel);
, where listmodel is a public instance.
The problem is, however, that as soon as a new user joins the server, the JList of the 1st (i.e. the oldest) client is updated while the rest of the users don't receive any updates to the JList in their UI.
In the notifyUser method, you are only writing to the output stream of the first user in the array, i.e.
i = 0;
It should be incremented after
out.get(i).flush();

Restricting file types upload component

I'm using the upload component of vaadin(7.1.9), now my trouble is that I'm not able to restrict what kind of files that can be sent with the upload component to the server, but I haven't found any API for that purpose. The only way is that of discarding file of wrong types after the upload.
public OutputStream receiveUpload(String filename, String mimeType) {
if(!checkIfAValidType(filename)){
upload.interruptUpload();
}
return out;
}
Is this a correct way?
No, its not the correct way. The fact is, Vaadin does provide many useful interfaces that you can use to monitor when the upload started, interrupted, finished or failed. Here is a list:
com.vaadin.ui.Upload.FailedListener;
com.vaadin.ui.Upload.FinishedListener;
com.vaadin.ui.Upload.ProgressListener;
com.vaadin.ui.Upload.Receiver;
com.vaadin.ui.Upload.StartedListener;
Here is a code snippet to give you an example:
#Override
public void uploadStarted(StartedEvent event) {
// TODO Auto-generated method stub
System.out.println("***Upload: uploadStarted()");
String contentType = event.getMIMEType();
boolean allowed = false;
for(int i=0;i<allowedMimeTypes.size();i++){
if(contentType.equalsIgnoreCase(allowedMimeTypes.get(i))){
allowed = true;
break;
}
}
if(allowed){
fileNameLabel.setValue(event.getFilename());
progressBar.setValue(0f);
progressBar.setVisible(true);
cancelButton.setVisible(true);
upload.setEnabled(false);
}else{
Notification.show("Error", "\nAllowed MIME: "+allowedMimeTypes, Type.ERROR_MESSAGE);
upload.interruptUpload();
}
}
Here, allowedMimeTypes is an array of mime-type strings.
ArrayList<String> allowedMimeTypes = new ArrayList<String>();
allowedMimeTypes.add("image/jpeg");
allowedMimeTypes.add("image/png");
I hope it helps you.
Can be done.
You can add this and it will work (all done by HTML 5 and most browsers now support accept attribute) - this is example for .csv files:
upload.setButtonCaption("Import");
JavaScript.getCurrent().execute("document.getElementsByClassName('gwt-FileUpload')[0].setAttribute('accept', '.csv')");
I think it's better to throw custom exception from Receiver's receiveUpload:
Upload upload = new Upload(null, new Upload.Receiver() {
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
boolean typeSupported = /* do your check*/;
if (!typeSupported) {
throw new UnsupportedImageTypeException();
}
// continue returning correct stream
}
});
The exception is just a simple custom exception:
public class UnsupportedImageTypeException extends RuntimeException {
}
Then you just simply add a listener if the upload fails and check whether the reason is your exception:
upload.addFailedListener(new Upload.FailedListener() {
#Override
public void uploadFailed(Upload.FailedEvent event) {
if (event.getReason() instanceof UnsupportedImageTypeException) {
// do your stuff but probably don't log it as an error since it's not 'real' error
// better would be to show sth like a notification to inform your user
} else {
LOGGER.error("Upload failed, source={}, component={}", event.getSource(), event.getComponent());
}
}
});
public static boolean checkFileType(String mimeTypeToCheck) {
ArrayList allowedMimeTypes = new ArrayList();
allowedMimeTypes.add("image/jpeg");
allowedMimeTypes.add("application/pdf");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
allowedMimeTypes.add("image/png");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.presentationml.presentation");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
for (int i = 0; i < allowedMimeTypes.size(); i++) {
String temp = allowedMimeTypes.get(i);
if (temp.equalsIgnoreCase(mimeTypeToCheck)) {
return true;
}
}
return false;
}
I am working with Vaadin 8 and I there is no change in Upload class.
FileUploader receiver = new FileUploader();
Upload upload = new Upload();
upload.setAcceptMimeTypes("application/json");
upload.setButtonCaption("Open");
upload.setReceiver(receiver);
upload.addSucceededListener(receiver);
FileUploader is the class that I created that handles the upload process. Let me know if you need to see the implementation.

Not able to get the right file path after uploading

I am able to upload a picture in my webapp with the struts2 framework, but i am not able to understand the path.
how to get the path of the image as a URL, so that i can use it for further processing in <img src="url"/>.
This is my action class source code and i have mentioned the URL returned in comments, but the URL does not make any sense to me. How can i decrypt it to actual URL ?
public class AddItemAction extends ActionSupport implements
ServletContextAware {
#Override
public void setServletContext(ServletContext arg0) {
// TODO Auto-generated method stub
}
File pic;
String picContentType;
String picFileName;
public File getPic() {
return pic;
}
public void setPic(File pic) {
this.pic = pic;
}
public String getPicContentType() {
return picContentType;
}
void setPicContentType(String picContentType) {
System.out.println("Setting conteent tuype" + picContentType);
this.picContentType = picContentType;
}
public void setPicFileName(String picFileName) {
this.picFileName = picFileName;
}
public String getPicFileName() {
return picFileName;
}
public String execute() {
File file = getPic();
String strFinalFullPathFileName = file.getAbsolutePath() + File.separator + picFileName;
System.out.println(strFinalFullPathFileName);
// This is the path returned
/*
* /Users/..../Catalina/localhost/.../upload_584d2719_13d5fdf593d__8000_00000000.tmp/IMG_20120526_083438.jpg
*
*
*/
return SUCCESS;
}
}
Uploaded artifacts should be stored outside the web app structure.
In addition, by default, the file upload interceptor deletes the temporary files created during the upload process. That should either be turned off, or the file should be copied to a known location so they can be either (a) streamed back via an action, or (b) served directly if you set up your container to serve static assets outside of the normal web structure.
seems like you are uploading your file to a temp folder, what you should do is move this file to a folder inside your web app
you case use request.getServletContext().getRealPath(YOUR_PATH) to get a path where to move the file
YOUR_PATH being something like "/uploadimage/img.png" => uploadimage being a folder directly in you webapp

Drag and Drop compressed files from swing to native [update]

I am trying to move files from a compressed archive to the native system (basycally, windows' eplorer) through drag and drop operations.
My only idea at this moment is to create a TransferHandler, which, when launched, will decompress the file in a temporary directory and set up that file as Transferable. Here is a snippet of code to make myself more clear:
private class FileTransferHandler extends TransferHandler {
protected Transferable createTransferable(JComponent c) {
List<File> files = new ArrayList<File>();
try {
File temp = createTempDirectory();
String path = temp.getAbsolutePath();
decompressTo(path);
files.add(new File(path));
} catch (Exception e) { e.printStackTrace(); };
return new FileTransferable(files);
}
public int getSourceActions(JComponent c) {
return COPY;
}
}
private class FileTransferable implements Transferable {
private List<File> files;
public FileTransferable(List<File> files) {
this.files = files;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{ DataFlavor.javaFileListFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.javaFileListFlavor);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return files;
}
}
(not valid anymore: The thing that puzzles me is that this way it somehow works: but only if after I release the mouse button I am not doing anything else.)
update: After more testing I observed that actually the file data is transferred from the temp directory to destination after I click in a zone that accepts that DataFlavor. If I click in a folder, the temp files are transferred to that folder. If I click in the console window, the path to the temp file appears in the console window.
So, if you please, I would like some pointers to direct me in the right way.
p.s.: the idea with decompressing to temp folder first came after observing that WinRar is doing the same thing.
p.p.s.: sorry if the question seems stupid, but I am mostly a web programmer just dabbling in desktop programming.
Well, this is apparently nearing the best results you can get.
I'll check your code when I have some time for it.

Categories

Resources