OpenNapDirectBrowse.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.xnap.plugin.opennap.net |
![]() |
![]() |
XNap 3 |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* XNap - A P2P framework and client.
*
* See the file AUTHORS for copyright information.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.xnap.plugin.opennap.net;
import javax.swing.Action;
import javax.swing.Icon;
import java.awt.event.ActionEvent;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Hashtable;
import org.apache.log4j.Logger;
import org.xnap.XNap;
import org.xnap.net.NetHelper;
import org.xnap.peer.Peer;
import org.xnap.plugin.Plugin;
import org.xnap.plugin.opennap.OpenNapPlugin;
import org.xnap.plugin.opennap.net.msg.ExceptionListener;
import org.xnap.plugin.opennap.net.msg.MessageHandler;
import org.xnap.plugin.opennap.net.msg.MessageListener;
import org.xnap.plugin.opennap.net.msg.client.DirectBrowseRequestMessage;
import org.xnap.plugin.opennap.net.msg.server.DirectBrowseAckMessage;
import org.xnap.plugin.opennap.net.msg.server.DirectBrowseErrorMessage;
import org.xnap.plugin.opennap.net.msg.server.ServerMessage;
import org.xnap.plugin.opennap.user.OpenNapUser;
import org.xnap.search.SearchFilter;
import org.xnap.search.SearchHandler;
import org.xnap.search.SearchResult;
import org.xnap.transfer.AbstractDownload;
import org.xnap.transfer.DefaultSegment;
import org.xnap.transfer.DownloadManager;
import org.xnap.transfer.Segment;
import org.xnap.transfer.action.AbstractStopAction;
import org.xnap.util.FiniteStateMachine;
import org.xnap.util.QuotedStringTokenizer;
import org.xnap.util.Scheduler;
import org.xnap.util.State;
import org.xnap.util.XNapTask;
public class OpenNapDirectBrowse extends AbstractDownload
implements ExceptionListener, MessageListener,
OpenNapBrowseInterface, SocketListener {
//--- Constant(s) ---
public static final int REQUEST_TIMEOUT = 2 * 60 * 1000;
public static final int SOCKET_TIMEOUT = 1 * 60 * 1000;
/**
* The state transition table.
*/
private static final Hashtable TRANSITION_TABLE;
static {
State[][] table = new State[][] {
{ State.NOT_STARTED,
State.REQUESTING, },
{ State.REQUESTING,
State.CONNECTING, State.FINISHED, State.STOPPING, },
{ State.CONNECTING,
State.DOWNLOADING, State.FINISHED, State.STOPPING, },
{ State.DOWNLOADING,
State.FINISHED, State.STOPPING, },
{ State.STOPPING,
State.FINISHED }
};
TRANSITION_TABLE = FiniteStateMachine.createStateTable(table);
}
//--- Data field(s) ---
protected static Logger logger = Logger.getLogger(OpenNapDirectBrowse.class);
private StateMachine sm = new StateMachine();
private OpenNapUser user;
private SearchHandler handler;
private BrowseDownloadSocket inSocket;
private long bytesTransferred;
private DefaultSegment segment;
private long size;
private boolean failed;
//--- Constructor(s) ---
public OpenNapDirectBrowse(OpenNapUser user)
{
this.user = user;
}
//--- Method(s) ---
public void exceptionThrown(Exception e)
{
failed = true;
setState(State.FINISHED, e.getLocalizedMessage());
}
public File getFile()
{
return null;
}
public String getFilename()
{
return XNap.tr("OpenNap Direct Browse");
}
/**
*
*/
public long getFilesize()
{
return size;
}
/**
* Returns <code>null</code>.
*/
public SearchFilter getFilter()
{
return null;
}
/**
* Returns the name of the user that is browsed.
*/
public String getName()
{
return user.getName();
}
public Plugin getPlugin()
{
return OpenNapPlugin.getInstance();
}
/**
* @see xnap.transfer.Transfer#getActions()
*/
public Action[] getActions()
{
return new Action[] { new StopAction() };
}
/**
*
*/
public long getBytesTransferred()
{
return bytesTransferred;
}
public Icon getIcon()
{
return OpenNapPlugin.ICON_16;
}
/**
* @see xnap.transfer.Transfer#getPeer()
*/
public Peer getPeer()
{
return user;
}
public Segment[] getSegments()
{
return (segment != null) ? new Segment[] { segment } : null;
}
/**
* @see xnap.transfer.Transfer#getStatus()
*/
public String getStatus()
{
return sm.getDescription();
}
/**
* @see xnap.transfer.Transfer#getTotalBytesTransferred()
*/
public long getTotalBytesTransferred()
{
return (isDone()) ? bytesTransferred : 0;
}
public boolean isDone()
{
return sm.getState() == State.FINISHED;
}
public boolean isFailed()
{
return failed;
}
public boolean isRunning()
{
return sm.getState() == State.DOWNLOADING;
}
/**
* Handles messages received from the server as response to the download
* request. Notifies the parent download container if download is ready to
* start or if it should be removed due to an error message received from
* the server.
*/
public void messageReceived(ServerMessage msg)
{
if (msg instanceof DirectBrowseErrorMessage) {
DirectBrowseErrorMessage m = (DirectBrowseErrorMessage)msg;
if (m.nick.equals(user.getName())) {
msg.consume();
setState(State.FINISHED, m.message);
}
}
else if (msg instanceof DirectBrowseAckMessage) {
DirectBrowseAckMessage m = (DirectBrowseAckMessage)msg;
if (m.nick.equals(user.getName())) {
msg.consume();
user.setHost(m.ip);
user.setPort(m.port);
setState(State.CONNECTING);
}
}
}
/**
* Returns <code>true</code>.
*/
public boolean showTree()
{
return true;
}
public boolean socketReceived(IncomingSocket s)
{
if (s instanceof BrowseDownloadSocket) {
// there is no way to verify if this socket is really ours
// so just take it
BrowseDownloadSocket b = (BrowseDownloadSocket)s;
if (user.getName().equals(b.nick)) {
inSocket = b;
setState(State.CONNECTING);
return true;
}
}
return false;
}
/**
* Starts this search.
*
* @param handler the object that handles the results
*/
public void start(SearchHandler handler)
{
this.handler = handler;
setState(State.REQUESTING);
}
/**
* Cancels this search.
*/
public void stop()
{
setState(State.STOPPING);
}
void setState(State newState, String description)
{
sm.setState(newState, description);
stateChanged();
handler.stateChanged(this);
}
void setState(State newState)
{
sm.setState(newState);
stateChanged();
handler.stateChanged(this);
}
//--- Inner Class(es) ---
private class StateMachine extends FiniteStateMachine {
//--- Data Field(s) ---
private OpenNapDirectBrowseDownloadRunner runner;
private Thread t;
private XNapTask watcher;
//--- Constructor(s) ---
public StateMachine()
{
super(State.NOT_STARTED, TRANSITION_TABLE);
}
//--- Method(s) ---
protected synchronized void stateChanged(State oldState,
State newState)
{
if (newState == State.REQUESTING) {
DownloadManager.getInstance().add(OpenNapDirectBrowse.this);
user.getServer().getListener().addSocketListener
(OpenNapDirectBrowse.this);
MessageHandler.subscribe(DirectBrowseAckMessage.TYPE,
OpenNapDirectBrowse.this);
MessageHandler.subscribe(DirectBrowseErrorMessage.TYPE,
OpenNapDirectBrowse.this);
DirectBrowseRequestMessage msg
= new DirectBrowseRequestMessage(user.getName());
msg.setExceptionListener(OpenNapDirectBrowse.this);
MessageHandler.send(user.getServer(), msg);
watcher = new WatchTask();
Scheduler.run(REQUEST_TIMEOUT, watcher);
}
else if (newState == State.CONNECTING) {
runner = new OpenNapDirectBrowseDownloadRunner(inSocket);
t = new Thread(runner, "OpenNapDirectBrowseDownload:"
+ user.getName());
t.start();
}
else if (newState == State.DOWNLOADING) {
transferStarted();
}
else if (newState == State.STOPPING) {
if (oldState == State.CONNECTING
|| oldState == State.DOWNLOADING) {
runner.stop();
t.interrupt();
}
else {
this.setState(State.FINISHED);
}
}
else if (newState == State.FINISHED) {
DownloadManager.getInstance().remove(OpenNapDirectBrowse.this);
}
if (oldState == State.REQUESTING) {
if (watcher != null) {
watcher.cancel();
watcher = null;
}
user.getServer().getListener().removeSocketListener
(OpenNapDirectBrowse.this);
MessageHandler.unsubscribe(DirectBrowseAckMessage.TYPE,
OpenNapDirectBrowse.this);
MessageHandler.unsubscribe(DirectBrowseErrorMessage.TYPE,
OpenNapDirectBrowse.this);
}
else if (oldState == State.DOWNLOADING) {
transferStopped();
}
}
}
private class WatchTask extends XNapTask
{
public void run()
{
synchronized (sm) {
if (sm.getState() == State.REQUESTING) {
failed = true;
sm.setState(State.FINISHED, "timeout");
}
}
stateChanged();
handler.stateChanged(OpenNapDirectBrowse.this);
}
}
private class StopAction extends AbstractStopAction
{
public void actionPerformed(ActionEvent e)
{
stop();
}
}
private class OpenNapDirectBrowseDownloadRunner implements Runnable
{
private boolean die;
private Socket socket;
private InputStream in;
private OutputStream out;
public OpenNapDirectBrowseDownloadRunner(BrowseDownloadSocket b)
{
if (b != null) {
socket = b.socket;
in = b.in;
}
}
public void run()
{
try {
if (socket != null) {
connect();
}
else {
connect(user.getHost(), user.getPort());
}
setState(State.DOWNLOADING);
download();
setState(State.FINISHED);
}
catch (IOException e) {
failed = true;
setState(State.FINISHED, NetHelper.getErrorMessage(e));
}
catch (InterruptedException e) {
failed = true;
setState(State.FINISHED, XNap.tr("Stopped"));
}
finally {
close();
}
}
public void stop()
{
die = true;
}
private void close()
{
try {
if (socket != null)
socket.close();
if (in != null)
in.close();
if (out != null)
out.close();
}
catch (IOException e) {
}
}
private void connect(String host, int port) throws IOException
{
logger.debug("connecting to " + host + ":" + port
+ " for direct browse");
socket = new Socket(host, port);
socket.setSoTimeout(SOCKET_TIMEOUT);
out = socket.getOutputStream();
in = new BufferedInputStream(socket.getInputStream());
// read magic number '1'
logger.debug("reading magic number");
char c = (char)in.read();
if (c != '1') {
throw new IOException(XNap.tr("Invalid request"));
}
write("GETLIST");
byte data[] = new byte[2048];
in.mark(2048);
int i = in.read(data);
if (i > 0) {
String nick = new String(data, 0, i);
int j = nick.indexOf("\n");
if (j == -1) {
// read '\n'
in.read();
}
else {
nick = nick.substring(0, j).trim();
in.reset();
in.skip(j + 1);
}
if (!nick.equals(user.getName())) {
throw new IOException("Invalid user: " + nick);
}
}
else {
throw new IOException("Socket error");
}
}
private void connect() throws IOException
{
socket.setSoTimeout(SOCKET_TIMEOUT);
out = socket.getOutputStream();
}
private void download() throws IOException, InterruptedException
{
BufferedReader reader
= new BufferedReader(new InputStreamReader(in));
int count = user.getFileCount();
if (count != -1) {
segment = new DefaultSegment(count);
}
String s;
count = 0;
while ((s = reader.readLine()) != null) {
if (die) {
throw new InterruptedException();
}
else if (s.length() == 0) {
break;
}
bytesTransferred += s.getBytes().length;
if (segment != null) {
segment.commit(1);
}
QuotedStringTokenizer t = new QuotedStringTokenizer(s);
if (t.countTokens() < 6) {
continue;
}
try {
String filename = t.nextToken();
String md5 = t.nextToken();
long size = Long.parseLong(t.nextToken());
int bitrate = Integer.parseInt(t.nextToken());
int frequency = Integer.parseInt(t.nextToken());
int length = Integer.parseInt(t.nextToken());
SearchResult result = new OpenNapSearchResult
(null, size, bitrate, frequency, length,
user, filename, md5);
handler.resultReceived(result);
}
catch (NumberFormatException e) {
}
}
}
private void write(String message) throws IOException
{
logger.debug("> " + message);
out.write(message.getBytes());
out.flush();
}
}
}
The table below shows all metrics for OpenNapDirectBrowse.java.



