Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /* ************************************************************************
  #
  #  DivConq
  #
  #  http://divconq.com/
  #
  #  Copyright:
  #    Copyright 2014 eTimeline, LLC. All rights reserved.
  #
 #  License:
 #    See the license.txt file in the project's top-level directory for details.
 #
 #  Authors:
 #    * Andy White
 #
 ************************************************************************ */
 package divconq.interchange;
 
 
 
 
 
 public class FileSystemFile extends RecordStruct implements IFileStoreFile {
 	protected FileSystemDriver driver = null;
 	protected Path localpath = null;
 		
 	public FileSystemFile() {
 		if (..getSchema() != null)
 			this.setType(..getSchema().getType("dciFileSystemFile"));
 	}
 
 	public FileSystemFile(FileSystemDriver driverPath file) {
 		this();
 		
 		this. = driver;
 		this. = file;
 		
 	}
 
 	public FileSystemFile(FileSystemDriver driverCommonPath file) {
 		this();
 		
 		this. = driver;
 		this. = driver.resolveToLocalPath(file);
 		
 	}
 
 	public FileSystemFile(FileSystemDriver driverCommonPath fileboolean folder) {
 		this();
 		
 		this. = driver;
 		this. = driver.resolveToLocalPath(file);
 		
 		this.setField("IsFolder"folder);
 		
 	}
 	
     public FileSystemFile(FileSystemDriver driverRecordStruct rec) {
		this();
		this. = driver;
		((RecordStructthis).copyFields(rec);
		// only works with relative paths - even if my path is / it is considered relative to root
		// which is good
		String cwd = driver.getFieldAsString("RootFolder");
		this. = Paths.get(cwdthis.getFieldAsString("Path"));
	}
    
    public void refreshProps() {
		// ignore what the caller told us, these are the right values:
		this.setField("Name"this..getFileName().toString());
		String cwd = this..getFieldAsString("RootFolder");
		String fpath = this..normalize().toString();
		// common path format in "absolute" relative to mount (TODO not relative to WF - fix instead relative to RootFolder)
		// also, since fpath may be absolute - only do substring thing if cwd is above fpath in folder chain TODO
		if (fpath.length() == cwd.length())
		this.setField("Path""/");
		else
		this.setField("Path""/" + fpath.substring(cwd.length() + 1).replace('\\''/'));
		this.setField("FullPath"fpath);
		if (Files.exists(this.)) {
			try {
				this.setField("Size", Files.size(this.));
				this.setField("Modified"new DateTime(Files.getLastModifiedTime(this.).toMillis()));
			catch (IOException x) {
			}
			this.setField("IsFolder", Files.isDirectory(this.));
			this.setField("Exists"true);
		}
		else
			this.setField("Exists"false);
    }
    
    @Override
    public boolean exists() {
    	return this.getFieldAsBooleanOrFalse("Exists");
    }
    
    @Override
    public CommonPath path() {
    	return new CommonPath(this.getFieldAsString("Path"));
    }
	public String getName() {
		return this.getFieldAsString("Name");
	}
	public void setName(String v) {
		this.setField("Name"v);
	}
	public String getPath() {
		return this.getFieldAsString("Path");
	}
	public void setPath(String v) {
		this.setField("Path"v);
	}
	public String getExtension() {
		return FileUtil.getFileExtension(this.getFieldAsString("Name"));
	}
	public String getFullPath() {
		return this.getFieldAsString("FullPath");
	}
		return this.getFieldAsDateTime("Modified");
	}
	public long getSize() {
		return this.getFieldAsInteger("Size", 0);
	}
	public boolean isFolder() {
		return this.getFieldAsBooleanOrFalse("IsFolder");
	}
	public void isFolder(boolean v) {
		this.setField("IsFolder"v);
	}
	public Path localPath() {
		return this.;
	}
		return this.;
	}
		if (this.isFolder())
			return this.path().resolve(path);
		return this.path().getParent().resolve(path);
	}
		if (this.isFolder())
			return new FileSystemScanner(this);
		return null;
	}
	public IStreamDest allocDest() {
		return new FileDestStream(this);
	}
	@SuppressWarnings("resource")
	public IStreamDest allocDest(boolean relative) {
		return new FileDestStream(this).withRelative(relative);
	}
	public IStreamSource allocSrc() {
    	if (this.isFolder()) 
    		return new FileSourceStream(this.scanner());
    	
    	FileCollection filesrc = new FileCollection();
		filesrc.add(this);
		return new FileSourceStream(filesrc);
	}
	/*
	@Override
	public Iterable<Struct> getItems() {
		if (this.driver == null)
			return null;
		String cwd = this.driver.getFieldAsString("RootFolder");
		Boolean recursive = this.getFieldAsBoolean("Recursive");
		ListStruct match = this.getFieldAsList("MatchFiles");
		List<String> wildcards = new ArrayList<String>();
		if (match != null) 
			for (Struct s : match.getItems()) 
				wildcards.add(((StringStruct)s).getValue());
		// see AndFileFilter and OrFileFilter
		IOFileFilter filefilter = new WildcardFileFilter(wildcards);
		// TODO support more options, size/date, folder filter
		return new Matches(new File(cwd), filefilter, 
				((recursive != null) && recursive) ? TrueFileFilter.TRUE : FalseFileFilter.FALSE);		
	}
	*/
    protected void doCopy(Struct n) {
    	super.doCopy(n);
    	
    	FileSystemFile nn = (FileSystemFile)n;
		nn.driver = this.;
    }
    
	public Struct deepCopy() {
		this.doCopy(cp);
		return cp;
	}
		if ("TextReader".equals(name)) {
			return res;
		}
		return super.getOrAllocateField(name);
	}
	public void operation(final StackEntry stackXElement code) {
		if ("Hash".equals(code.getName())) {
			String meth = stack.stringFromElement(code"Method");
	        final Struct var = stack.refFromElement(code"Target");
			if (var instanceof ScalarStruct) { 				
				this.hash(methnew FuncCallback<String>() {					
					public void callback() {
						stack.resume();
					}
				});
				return;
			}
			else {
				stack.log().error(1, "Invalid hash target!");
			}
			stack.resume();
			return;
		}
		if ("Rename".equals(code.getName())) {
			String val = stack.stringFromElement(code"Value");
			// TODO support other methods
			if (StringUtil.isEmpty(val)) {
				// TODO log
				stack.resume();
				return;
			}
			Path dest = this..getParent().resolve(val);
			try {
				Files.move(this.dest);
				this. = dest;
			catch (IOException x) {
				// TODO catch?
			}
			stack.resume();
			return;
		}
		// this is kind of a hack - may want to re-evaluate this later
		// used by NCC provisioning
		if ("WriteText".equals(code.getName())) {
			String text = code.getText();
	        Struct content = StringUtil.isNotEmpty(text
	        		? stack.resolveValue(text)
	        		: stack.refFromElement(code"Target");
	        
	        if (content != null) {
	        	OperationResult or = IOUtil.saveEntireFile(this., Struct.objectToString(content));
	        	
	        	stack.log().copyMessages(or);
	        	
	        	this.refreshProps();
	        }
			stack.resume();
			return;
		}
		// this is kind of a hack - may want to re-evaluate this later
		// used by NCC provisioning
		if ("ReadText".equals(code.getName())) {
			if (this.getFieldAsBooleanOrFalse("Exists")) {
		        final Struct var = stack.refFromElement(code"Target");
		        //System.out.println("e: " + var);
		        
				if (var instanceof NullStruct) {					
			        String handle = stack.stringFromElement(code"Handle");
					if (handle != null
			            stack.addVariable(handlenew StringStruct(IOUtil.readEntireFile(this..toFile())));
					// TODO log
				}			
				else if (var instanceof ScalarStruct) {					
				}
				else {
					// TODO log
				}
			}
			stack.resume();
			return;
		}
		if ("Delete".equals(code.getName())) {
			try {
				if (this.isFolder())
					FileUtil.deleteDirectory(this.);
				else
			catch (IOException x) {
				// TODO Auto-generated catch block
			}
	    	this.refreshProps();
	    	
			stack.resume();
			return;
		}
		/*
		if ("ScanFilter".equals(code.getName())) {
			String path = stack.stringFromElement(code, "Path");
			...
			if (StringUtil.isEmpty(path)) {
				// TODO log
				stack.resume();
				return;
			}
			this.cwd = new File(path);
			stack.resume();
			return;
		}
		*/
		super.operation(stackcode);
	}
	// TODO use DataStreamChannel instead
	/*
	@Override
	public void copyTo(OutputStream out, OperationCallback callback) {
		try {
			Files.copy(this.localpath, out);
			out.flush();
			out.close();
		catch (IOException x) {
			callback.error(1, "Unable to write file");		// TODO codes
		}		
		finally {
            IOUtil.closeQuietly(out);			
		}
		callback.completed();
	}
	*/
	public class DestinationDriver implements IFileStoreStreamDriver {						
		protected FileChannel fchannel = null;
		protected DataStreamChannel channel = null;
		protected Path file = null;
		protected ReentrantLock accesslock = new ReentrantLock();
		protected CommonPath path = null;
		protected long expectedsize = 0;
		protected long writtensize = 0;

At this point we don't have a channel yet, so we don't need to communicate any errors to a channel in this method
		public void init(DataStreamChannel channelOperationCallback or) {
			this. = channel;
			RecordStruct rec = channel.getBinding();
			this. = new CommonPath(rec.getFieldAsString("FilePath"));
			this. = rec.getFieldAsInteger("FileSize", 0);
			boolean exists = Files.exists(this.);
			or.info("Opening " + this. + " for write - check exists: " + exists);
			OperationResult mdres = FileUtil.confirmOrCreateDir(this..getParent());
			or.copyMessages(mdres);
			if (mdres.hasErrors()) {
	        	or.error("FS failed to open file: " + this.);
	        	or.complete();				
			}
	        try {
				boolean append = rec.getFieldAsBooleanOrFalse("Append");
	        	
	        	if (append && exists) {
	        		//or.info("Appending to " + this.file + " initial result for size: " + Files.size(this.file));
	        		
	        		// TODO maybe put the local locking back in we had before? - useful here and for integrity checks - not useful in distributed deployment?
	        		// experience shows that we are not always getting the correct size, if we wait a but maybe it will flush out? 
	        		Thread.sleep(5000);
	        		
	        		this. = FileChannel.open(this....);
	        		
	        		// this should be a reliable way to get position - better than Files.size hopefully
	        		long size = this..position();
	        		
	        		or.info("Appending to " + this. + " current size: " + size);
	        		FileSystemFile.this.setField("Size"size);
	        		
	        		if (this. < size) {
	        			this..close();
	        			or.error("File size exceeds the Expected Size");
	        			return;
	        		}
	        		
	        		if (this. == size
	        			or.warn("Resume attempted on an already completed upload.  File size and Expected Size match.");
	        	}
	        	else {
	        		// better than delete - you never know when the delete will complete, but this will do it all - remove and then write
	        		FileSystemFile.this.setField("Size", 0);
	        	}
	        } 
	        catch (IOException x) {
	        	or.error(1, "FS failed to open file: " + x);
	        }
	        catch (InterruptedException x) {
	        	or.error(1, "FS failed to open file: " + x);
	        }
	        
		}
		public void nextChunk() {
			// ignore, meaningless
		}
		public void message(StreamMessage msg) {
			this..touch();
	    	// TODO fill in this.channel.setProgress
	    	
	    	// would only happen if message after Final or after cancel
	    	if (this. == null) {
	    		this..error(1, "Got message after final or cancel");
            	msg.release();
	    		return;
	    	}
	    	
	    	if (msg.hasData()) {
	            ByteBuf bb = msg.getData(); 
	    		
	    		if (bb.nioBufferCount() > 0) {
	    			// discourage close during write - just in case there is an abort/melt-down
	    			this..lock();
	    			
					try {
						this. += this..write(bb.nioBuffers());
						if (this. > 0)
							this..setAmountCompleted((int)(this. * 100 / this.));
	    			catch (IOException x) {
	    	    		this..error(1, "Error writing file");
	    				this..send(MessageUtil.streamError(1, "File write error!"));
	    	    		this.flushClose("UploadError");
					}
					finally {
					}
	    		}
	    	}
	    	
	    	if (msg.isFinal()) {
	    		// let them know we ended as expected
				this..send(MessageUtil.streamFinal());
				// must come after we send last message, closing will remove the channel
	    		this.flushClose("UploadComplete");				
	    	}
	    	// now we are done with the buffer, if any
        	msg.release();
		}
		public void flushClose(String event) {
			try {
		    	// we are done with the file
		    	if (this. != null)
					try {
						this..force(true);
		    		catch (IOException x) {
		    			Logger.error("Destination driver unable to close file " + this. + " error: " + x);
					}
			}
			finally {
		    	this. = null;
		    	
			}
		}
		public void cancel() {
			this.flushClose("UploadError");
		}
	}	
	public class SourceDriver implements IFileStoreStreamDriver {			
		protected AsynchronousFileChannel sbc = null;
		protected DataStreamChannel channel = null;
		protected Path file = null;
		protected ReentrantLock closelock = new ReentrantLock();
		protected CommonPath path = null;
		protected long offset= 0;
		public void init(DataStreamChannel channelOperationCallback or) {
			this. = channel;
			RecordStruct rec = channel.getBinding();
			this. = new CommonPath(rec.getFieldAsString("FilePath"));
			this. = rec.getFieldAsInteger("Offset", 0);
	        if (!Files.exists(this.)) {
	    		or.error(1, "FS failed to find file: " + this.);
				return;
	        }
	        
	        if (Files.isDirectory(this.)) {
	        	or.error(1, "FS found directory: " + this.);
				return;
	        }
	        
			or.info("Opening " + this. + " for read");
	        
	        try {
	        	this. = AsynchronousFileChannel.open(this.);
	        	
	        	// TODO skip to offset
	        } 
	        catch (IOException x) {
	        	or.error(1, "FS failed to open file: " + x);
	        }
		}
		public void nextChunk() {
			// ignore, meaningless
		}
		public void message(final StreamMessage msg) {
	    	if (this. == null) {
	    		this..error(1, "Got message after final or cancel");
	    		return;
	    	}
	        
	    	if (!msg.isStart()) {
	    		this..error(1, "Got message other than Start - expected Start");
	    		SourceDriver.this..send(MessageUtil.streamError(1, "Invalid request - channel cancelled!"));
	            this..close();
	    		return;
	    	}
	    	
	        try {
	            final ByteBuffer buf = ByteBuffer.allocate(64 * 1024);
	            final long fsize = Files.size(this.);
				final AtomicLong amtleft = new AtomicLong(fsize - this.);
				this..read(buf, 0, this.new CompletionHandler<IntegerAsynchronousFileChannel>() {
	            	long pos = 0;
	            	long seq = 0;
	            	
					public void completed(Integer resultAsynchronousFileChannel sbc) {
			    		if (SourceDriver.this..isClosed())
			    			return;
			    		SourceDriver.this..touch();
						if (result == -1) {
							SourceDriver.this.flushClose("DownloadComplete");
							SourceDriver.this..info(0, "File sent!!");
							return;
						}
				    	
						SourceDriver.this..setAmountCompleted((int)((fsize - amtleft.get()) * 100 / fsize));
						if (result > 0) {
							this. += result;
				            
							amtleft.getAndAdd(-result);
							StreamMessage b = new StreamMessage(amtleft.get() <= 0 ? "Final" : "Block"buf);
							b.setField("Sequence");
					        
							if (sr.hasErrors()) {
								SourceDriver.this.flushClose("DownloadError");
								SourceDriver.this..info(0, "File sending aborted!!");
								return;
							}
							++;
					        buf.clear();
						}
						// TODO add throttling options - put the read in "future" schedule
						sbc.read(bufthis.sbcthis);
					}
					public void failed(Throwable xAsynchronousFileChannel sbc) {
						SourceDriver.this..error(1, "Server Stream failed to read file: " + x);		            
						SourceDriver.this..send(MessageUtil.streamError(1, "File download read error!"));		            
						// cancel will be triggered by abort, don't close here
					}
				});
	        catch (IOException x) {
	        	SourceDriver.this..error(1, "Server Stream failed to read file: " + x);            
	        	SourceDriver.this..send(MessageUtil.streamError(1, "File download read error!"));            
	        	SourceDriver.this..abort();						
				// cancel will be triggered by abort, don't close here
			}
		}
		public void cancel() {
	        this.flushClose("DownloadError");
		}
		public void flushClose(String event) {
			try {
		    	// we are done with the file
		    	if (this. != null)
					try {
						this..close();
		    		catch (IOException x) {
		    			SourceDriver.this..error("Source driver unable to close file " + this. + " error: " + x);
					}
			}
			finally {
		    	this. = null;
		    	
			}
		}
	}
	public void openRead(final DataStreamChannel channelfinal FuncCallback<RecordStructcallback) {
		final SourceDriver d = new SourceDriver();
		d.init(channelnew OperationCallback() {			
			public void callback() {
				callback.copyMessages(this);
				if (!this.hasErrors()) {
					channel.setDriver(d);
					RecordStruct resp = new RecordStruct();
					resp.setField("Hub", OperationContext.getHubId());
					resp.setField("Session"channel.getSessionId());
					resp.setField("Channel"channel.getId());
					resp.setField("Size"FileSystemFile.this.getFieldAsInteger("Size"));
					callback.setResult(resp);
				}
				callback.complete();
			}
		});
	}
	public void openWrite(final DataStreamChannel channelfinal FuncCallback<RecordStructcallback) {
		try {
		catch (IOException x) {
			callback.error(1, "Unable to create destination folder path: " + x);
			callback.complete();
			return;
		}
		d.init(channelnew OperationCallback() {			
			public void callback() {
				callback.copyMessages(this);
				// we cannot get reliable size info this way because windows is sometimes too slow
				// about reporting file size.  we need to get file size instead by allowing dest driver 
				// to set size for us
				//FileSystemFile.this.refreshProps();
				if (!this.hasErrors()) {
					channel.setDriver(d);
					RecordStruct resp = new RecordStruct();
					resp.setField("Hub", OperationContext.getHubId());
					resp.setField("Session"channel.getSessionId());
					resp.setField("Channel"channel.getId());
					resp.setField("Size"FileSystemFile.this.getFieldAsInteger("Size"));
					callback.setResult(resp);
				}
				callback.complete();
			}
		});
	}
	public void hash(String methodFuncCallback<Stringcallback) {
		try {
			FuncResult<Stringres = HashUtil.hash(method, Files.newInputStream(this.));
			callback.copyMessages(res); 
			if (!res.hasErrors())
				callback.setResult(res.getResult());
		}
		catch (Exception x) {
			callback.error(1, "Unable to read file for hash: " + x);
		}
		callback.complete();
	}
	// TODO use DataStreamChannel instead
	/*
	@Override
	public void getInputStream(FuncCallback<InputStream> callback) {
		try {
			callback.setResult(Files.newInputStream(this.localpath));
		}
		catch (Exception x) {
			// TODO log
		}
		callback.completed();
	}
	*/
	public void rename(String nameOperationCallback callback) {
		// TODO Auto-generated method stub
	}
	public void remove(OperationCallback callback) {
		if (this.exists()) {
			if (this.isFolder()) {
				FileUtil.deleteDirectory(callbackthis.);
			}
			else  {
				try {
					Files.delete(this.);
				}
				catch (Exception x) {
					callback.error("Unable to remove file: " + this.getPath() + " - Error: " + x);
				}
			}
		}
		callback.complete();
	}
	public void setModificationTime(DateTime timeOperationCallback callback) {
		// TODO Auto-generated method stub
	}
	public void getAttribute(String nameFuncCallback<Structcallback) {
		// TODO Auto-generated method stub
	}
	public void setAttribute(String nameStruct value,
			OperationCallback callback) {
		// TODO Auto-generated method stub
	}
New to GrepCode? Check out our FAQ X