java.nio.channels.NonWritableChannelException thrown when requesting a FileChannel Lock

Hi all,

I'm trying to learn how to use file locks.  The examples on the web seem to be pretty straightforward, but when I try to use locks in my code, I get the NonWritableChannelException error.

So far I'm just trying to create and release the FileChannel and the lock in some existing code I'm working on.  As you can imagine from the code below, the System.out.printlns are there just so I can see in the output where things are happening.

In the bigger picture, the code is supposed to read a JTree from the disk, cast it to JTree and, in later code, refresh the tree to reflect the loaded info.  The plan is for multiple people to use this application over a network and be able to save any changes.  This is my first time using file locks.

Anyone have any ideas?
try{
	FileInputStream fin = new FileInputStream( reply ) ;
	System.out.println( "1" ) ;
	FileChannel channel = fin.getChannel( ) ;
	System.out.println( "2" ) ;
	FileLock lock = channel.tryLock( 0, channel.size( ), false ) ; -- Line 226
	System.out.println( "3" ) ;
 
	if( lock == null ){
		throw new Error( "No Lock. :(" ) ;
	}
	
	ObjectInputStream objin = new ObjectInputStream( fin ) ;
	equipmentTree = (JTree)objin.readObject( ) ;
 
	lock.release( ) ;
	channel.close( ) ;
	objin.close( ) ;
	fin.close( ) ;
}
catch( Exception e ){
	e.printStackTrace( System.out ) ;
	//	Reload the default tree
	reloadTree( ) ;
}
 
--------------------------------------------------
 
Output:
1
2
java.nio.channels.NonWritableChannelException
	at sun.nio.ch.FileChannelImpl.tryLock(Unknown Source)
	at DavitaTree.ProgUI.loadTree(DavitaUI.java:226)
	at DavitaTree.ProgMenu.actionPerformed(DavitaMenu.java:89)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.AbstractButton.doClick(Unknown Source)
	at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
	at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

Open in new window

LVL 6
Tony O'ByrneSenior Web DeveloperAsked:
Who is Participating?
 
objectsConnect With a Mentor Commented:
sorry misread your code.
you want to follow ksivananth's earlier suggestion and use the stream to read from, though you should create the stream after you acquire the lock


              RandomAccessFile raf = new RandomAccessFile( file, "rw" ) ;
              FileChannel channel = raf.getChannel( ) ;
              FileLock lock = channel.tryLock( 0, channel.size( ), false ) ;
      
              if( lock == null ){
                      throw new Error( "No Lock. :(" ) ;
              }
      
              InputStream in = new FileInputStream(file);
                ...

0
 
objectsCommented:
you trying to lock an input stream. input streams are read only

0
 
ksivananthCommented:
0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
CEHJCommented:
Try creating the channel read-only:
FileChannel channel = new RandomAccessFile(reply, "r").getChannel();

Open in new window

0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
Using RandomAccessFile I get the following error:
The constructor ObjectInputStream(RandomAccessFile) is undefined

If I use RandomAccessFile, I need some other way to read an object from a file.

I understand that input streams are read only, but why does that present issues when I try to obtain a lock?  Is lock information written to the file itself?  If I try to lock something that's read only, wouldn't CEHJ's comment also fail? (because of the RandomAccessFile(reply, "r") istead of being "rw"?)
0
 
ksivananthCommented:
>>Using RandomAccessFile I get the following error:
The constructor ObjectInputStream(RandomAccessFile) is undefined
>>

you can use the RandomAccessFile logic to lock the file and then use the stream to construct ObjectInputStream!
0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
ksivananth,

I tried several things based on what you suggested, and considering my results, I guess I don't understand what you mean, or how to achieve what I think you mean.

I've tried creating the randomAccessFile and getting the lock, then creating the FileInputStream and reading in from there.  But I get a file is locked exception.  Which makes sense - I locked it.

I then tried reading the randomAccessFile into a few different types of InputStreams.  Some wouldn't accept the randomAccessFile as a parameter to the respective constructors, but I did see on the sun website (http://java.sun.com/javase/technologies/core/basic/serializationFAQ.jsp#random) that using ByteArray[Input|Output]Stream was the way to go.

So I tried the code posted below.  However I got:
[ java.io.StreamCorruptedException: invalid stream header: 00000000 ] on line 237.

Is the ByteArray[Input|Output]Stream the way to go with this?  Or did you have something else in mind?
try{
	RandomAccessFile raf = new RandomAccessFile( reply, "rw" ) ;
	FileChannel channel = raf.getChannel( ) ;
	FileLock lock = channel.tryLock( 0, channel.size( ), false ) ;
 
	if( lock == null ){
		throw new Error( "No Lock. :(" ) ;
	}
 
	byte[] byteArray = new byte[(int)raf.length( )] ;
	ByteArrayInputStream bais = new ByteArrayInputStream( byteArray ) ;
 
	ObjectInputStream objin = new ObjectInputStream( bais ) ;	--	Line 237
 
	equipmentTree = (JTree)objin.readObject( ) ;
 
	lock.release( ) ;
	channel.close( ) ;
	objin.close( ) ;
	raf.close( ) ;
}

Open in new window

0
 
objectsCommented:
you can't use the file, you are already using it as a lock.
What is it you are trying to achieve?

0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
The application will load the tree information when it starts up.  The application will be used on multiple computers over a network and will need this information.  The application is for the tracking of equipment that's moved around to different locations, so everyone who will be using the app needs to know what everyone else has done.  Therefore, everyone would ideally have access to the one datafile.

Naturally, if two people start working on it at the same time, weird things can happen if they load the same information, but then save different information.  So I want to lock the file when it's opened.  I know that in the code above I close the lock almost right away, but right now, I'm just concerned with getting the process down.

In the case of the single user, I want to open and read the file, make sure it's locked, and later, write the updated tree to the file, and release the lock.
0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
I do understand that I may be going about this the wrong way...  That's why I'm here; I've never done this before.  I've looked at online examples, including the one mentioned above.  So far as I can see, some of the online examples have almost the exact same code that I posted at the start of this thread.  For example: http://stackoverflow.com/questions/421833/when-using-javas-filelock-is-it-ok-to-let-close-to-automatically-do-a-lock-re does the exact same thing as I do at the start - InputStream followed by Channel followed by Lock followed by read.
0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
Great! :-)  It all seems like it should be working - I've got my code exactly as you suggest, objects, but now, I'm getting an error on the line that actually reads the data -
ObjectInputStream objin = new ObjectInputStream( in ) ;

The error is:
java.io.IOException: The process cannot access the file because another process has locked a portion of the file

Any ideas as to what that other process may be?  It's particularly confusing to me since this process obviously has the lock.
0
 
ksivananthConnect With a Mentor Commented:
may be you can try reading the data from channel and then create a ByteArrayInputStream. Now you can create ObjectInputStream using the ByteArrayInputStream.

the whole idea is to read and write data through the channel through which you have aquired lock!
0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
Ok, it looks like we've finally gotten it working. :)
No exceptions thrown, no nothing - the tree loads real good.  All I need to do now is test and award points.

Thanks for all your help folks. :)

For anyone who stumbles upon this thread later, the code is below.
try{
	RandomAccessFile raf = new RandomAccessFile( reply, "rw" ) ;
	FileChannel channel = raf.getChannel( ) ;
	FileLock lock = channel.tryLock( 0, channel.size( ), false ) ;
 
	if( lock == null ){
		throw new Error( "No Lock. :(" ) ;
	}
 
	byte[] byteArray = new byte[(int)raf.length( )] ;
	ByteBuffer byteBuffer = ByteBuffer.wrap( byteArray ) ;
	channel.read( byteBuffer ) ;
 
	ByteArrayInputStream inStream = new ByteArrayInputStream( byteArray ) ;
 
	ObjectInputStream objin = new ObjectInputStream( inStream ) ;
 
	equipmentTree = (JTree)objin.readObject( ) ;
 
	inStream.close( ) ;
	lock.release( ) ;
	channel.close( ) ;
	objin.close( ) ;
	raf.close( ) ;
}

Open in new window

0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
Thanks guys.  Your guidance without throwing a completed solution helped me figure out a solution that worked with my code.
All the best,
Tony. :)
0
 
ksivananthCommented:
Glad you got it working but the one you have accepted is not the right one!
0
 
Tony O'ByrneSenior Web DeveloperAuthor Commented:
I was trying to accept both, and award points to both objects and ksivananth...

The way I was reading, objects confirmed that I need to create the lock then use the stream after the lock, and in your response you said that the ByteArrayInputStream was the way to go, and to read through the channel.

If it's a matter of how the points were shared, I guess you did offer the larger portion of the solution - is it possible for me to change the points?  I guess I was trying to be sure that points were awarded for the contributions.  If it's a matter of which, and not whose, reply, well then I truly have no idea which one was the solution...

So far as I can understand, the general method was
Create lock
Read through Channel
Create inputStream (using ByteArrayInputStream)

This was my first ever post.  Help me understand how the etiquette goes? :-)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.