Solved

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

Posted on 2009-03-30
16
3,673 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
Comment Utility
you trying to lock an input stream. input streams are read only

0
 
LVL 26

Expert Comment

by:ksivananth
Comment Utility
0
 
LVL 86

Expert Comment

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

Open in new window

0
 
LVL 6

Author Comment

by:Tony O'Byrne
Comment Utility
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
Comment Utility
>>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
Comment Utility
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
Comment Utility
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
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 6

Author Comment

by:Tony O'Byrne
Comment Utility
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 250 total points
Comment Utility
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
Comment Utility
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 250 total points
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
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 will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.

728 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now