?
Solved

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

Posted on 2009-03-30
16
Medium Priority
?
4,809 Views
Last Modified: 2012-05-06
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

0
Comment
Question by:Tony O'Byrne
  • 8
  • 4
  • 3
  • +1
16 Comments
 
LVL 92

Expert Comment

by:objects
ID: 24025985
you trying to lock an input stream. input streams are read only

0
 
LVL 26

Expert Comment

by:ksivananth
ID: 24026477
0
 
LVL 86

Expert Comment

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

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 6

Author Comment

by:Tony O'Byrne
ID: 24029603
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
 
LVL 26

Expert Comment

by:ksivananth
ID: 24029922
>>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
 
LVL 6

Author Comment

by:Tony O'Byrne
ID: 24033834
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
 
LVL 92

Expert Comment

by:objects
ID: 24034124
you can't use the file, you are already using it as a lock.
What is it you are trying to achieve?

0
 
LVL 6

Author Comment

by:Tony O'Byrne
ID: 24035678
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
 
LVL 6

Author Comment

by:Tony O'Byrne
ID: 24035710
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
 
LVL 92

Accepted Solution

by:
objects earned 1000 total points
ID: 24035793
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
 
LVL 6

Author Comment

by:Tony O'Byrne
ID: 24041795
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
 
LVL 26

Assisted Solution

by:ksivananth
ksivananth earned 1000 total points
ID: 24047058
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
 
LVL 6

Author Comment

by:Tony O'Byrne
ID: 24050624
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
 
LVL 6

Author Closing Comment

by:Tony O'Byrne
ID: 31564698
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
 
LVL 26

Expert Comment

by:ksivananth
ID: 24050898
Glad you got it working but the one you have accepted is not the right one!
0
 
LVL 6

Author Comment

by:Tony O'Byrne
ID: 24055875
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

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Java functions are among the best things for programmers to work with as Java sites can be very easy to read and prepare. Java especially simplifies many processes in the coding industry as it helps integrate many forms of technology and different d…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
Suggested Courses
Course of the Month16 days, 9 hours left to enroll

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question