We are using Example 3 from this URL to broadcast streaming from Android camera device to server , we change code only to connect with our server not with Wowza server but the video is not arrive to server or by another meaning the input stream file is arriving empty to server for video but the audio is arriving perfectly , sometimes the connection with server is lost after some seconds , How we can know if this problem from server side or from client (code) side , We are using the same code here with change ip address and port number of our server.
https://github.com/fyhertz/libstreaming
The encoding process may be effect in this case?
Session Builder
public class SessionBuilder {
public final static String TAG = "SessionBuilder";
/** Can be used with {#link #setVideoEncoder}. */
public final static int VIDEO_NONE = 0;
/** Can be used with {#link #setVideoEncoder}. */
public final static int VIDEO_H264 = 1;
/** Can be used with {#link #setVideoEncoder}. */
public final static int VIDEO_H263 = 2;
/** Can be used with {#link #setAudioEncoder}. */
public final static int AUDIO_NONE = 0;
/** Can be used with {#link #setAudioEncoder}. */
public final static int AUDIO_AMRNB = 3;
/** Can be used with {#link #setAudioEncoder}. */
public final static int AUDIO_AAC = 5;
// Default configuration
private VideoQuality mVideoQuality = VideoQuality.DEFAULT_VIDEO_QUALITY;
private AudioQuality mAudioQuality = AudioQuality.DEFAULT_AUDIO_QUALITY;
private Context mContext;
private int mVideoEncoder = VIDEO_H263;
private int mAudioEncoder = AUDIO_AMRNB;
private int mCamera = CameraInfo.CAMERA_FACING_BACK;
private int mTimeToLive = 64;
private int mOrientation = 0;
private boolean mFlash = false;
private SurfaceView mSurfaceView = null;
private String mOrigin = null;
private String mDestination = null;
private Session.Callback mCallback = null;
// Removes the default public constructor
private SessionBuilder() {}
// The SessionManager implements the singleton pattern
private static volatile SessionBuilder sInstance = null;
/**
* Returns a reference to the {#link SessionBuilder}.
* #return The reference to the {#link SessionBuilder}
*/
public final static SessionBuilder getInstance() {
if (sInstance == null) {
synchronized (SessionBuilder.class) {
if (sInstance == null) {
SessionBuilder.sInstance = new SessionBuilder();
}
}
}
return sInstance;
}
/**
* Creates a new {#link Session}.
* #return The new Session
* #throws IOException
*/
public Session build() {
Session session;
session = new Session();
session.setOrigin(mOrigin);
session.setDestination(mDestination);
session.setTimeToLive(mTimeToLive);
session.setCallback(mCallback);
switch (mAudioEncoder) {
case AUDIO_AAC:
AACStream stream = new AACStream();
session.addAudioTrack(stream);
if (mContext!=null)
stream.setPreferences(PreferenceManager.getDefaultSharedPreferences(mContext));
break;
case AUDIO_AMRNB:
session.addAudioTrack(new AMRNBStream());
break;
}
switch (mVideoEncoder) {
case VIDEO_H263:
session.addVideoTrack(new H263Stream(mCamera));
break;
case VIDEO_H264:
H264Stream stream = new H264Stream(mCamera);
if (mContext!=null)
stream.setPreferences(PreferenceManager.getDefaultSharedPreferences(mContext));
session.addVideoTrack(stream);
break;
}
if (session.getVideoTrack()!=null) {
VideoStream video = session.getVideoTrack();
video.setFlashState(mFlash);
video.setVideoQuality(mVideoQuality);
video.setSurfaceView(mSurfaceView);
video.setPreviewOrientation(mOrientation);
video.setDestinationPorts(5006);
}
if (session.getAudioTrack()!=null) {
AudioStream audio = session.getAudioTrack();
audio.setAudioQuality(mAudioQuality);
audio.setDestinationPorts(5004);
}
return session;
}
/**
* Access to the context is needed for the H264Stream class to store some stuff in the SharedPreferences.
* Note that you should pass the Application context, not the context of an Activity.
**/
public SessionBuilder setContext(Context context) {
mContext = context;
return this;
}
/** Sets the destination of the session. */
public SessionBuilder setDestination(String destination) {
mDestination = destination;
return this;
}
/** Sets the origin of the session. It appears in the SDP of the session. */
public SessionBuilder setOrigin(String origin) {
mOrigin = origin;
return this;
}
/** Sets the video stream quality. */
public SessionBuilder setVideoQuality(VideoQuality quality) {
mVideoQuality = quality.clone();
return this;
}
/** Sets the audio encoder. */
public SessionBuilder setAudioEncoder(int encoder) {
mAudioEncoder = encoder;
return this;
}
/** Sets the audio quality. */
public SessionBuilder setAudioQuality(AudioQuality quality) {
mAudioQuality = quality.clone();
return this;
}
/** Sets the default video encoder. */
public SessionBuilder setVideoEncoder(int encoder) {
mVideoEncoder = encoder;
return this;
}
public SessionBuilder setFlashEnabled(boolean enabled) {
mFlash = enabled;
return this;
}
public SessionBuilder setCamera(int camera) {
mCamera = camera;
return this;
}
public SessionBuilder setTimeToLive(int ttl) {
mTimeToLive = ttl;
return this;
}
/**
* Sets the SurfaceView required to preview the video stream.
**/
public SessionBuilder setSurfaceView(SurfaceView surfaceView) {
mSurfaceView = surfaceView;
return this;
}
/**
* Sets the orientation of the preview.
* #param orientation The orientation of the preview
*/
public SessionBuilder setPreviewOrientation(int orientation) {
mOrientation = orientation;
return this;
}
public SessionBuilder setCallback(Session.Callback callback) {
mCallback = callback;
return this;
}
/** Returns the context set with {#link #setContext(Context)}*/
public Context getContext() {
return mContext;
}
/** Returns the destination ip address set with {#link #setDestination(String)}. */
public String getDestination() {
return mDestination;
}
/** Returns the origin ip address set with {#link #setOrigin(String)}. */
public String getOrigin() {
return mOrigin;
}
/** Returns the audio encoder set with {#link #setAudioEncoder(int)}. */
public int getAudioEncoder() {
return mAudioEncoder;
}
/** Returns the id of the {#link android.hardware.Camera} set with {#link #setCamera(int)}. */
public int getCamera() {
return mCamera;
}
/** Returns the video encoder set with {#link #setVideoEncoder(int)}. */
public int getVideoEncoder() {
return mVideoEncoder;
}
/** Returns the VideoQuality set with {#link #setVideoQuality(VideoQuality)}. */
public VideoQuality getVideoQuality() {
return mVideoQuality;
}
/** Returns the AudioQuality set with {#link #setAudioQuality(AudioQuality)}. */
public AudioQuality getAudioQuality() {
return mAudioQuality;
}
/** Returns the flash state set with {#link #setFlashEnabled(boolean)}. */
public boolean getFlashState() {
return mFlash;
}
/** Returns the SurfaceView set with {#link #setSurfaceView(SurfaceView)}. */
public SurfaceView getSurfaceView() {
return mSurfaceView;
}
/** Returns the time to live set with {#link #setTimeToLive(int)}. */
public int getTimeToLive() {
return mTimeToLive;
}
/** Returns a new {#link SessionBuilder} with the same configuration. */
public SessionBuilder clone() {
return new SessionBuilder()
.setDestination(mDestination)
.setOrigin(mOrigin)
.setSurfaceView(mSurfaceView)
.setPreviewOrientation(mOrientation)
.setVideoQuality(mVideoQuality)
.setVideoEncoder(mVideoEncoder)
.setFlashEnabled(mFlash)
.setCamera(mCamera)
.setTimeToLive(mTimeToLive)
.setAudioEncoder(mAudioEncoder)
.setAudioQuality(mAudioQuality)
.setContext(mContext)
.setCallback(mCallback);
}
}
Session Class:
public class Session {
public final static String TAG = "Session";
public final static int STREAM_VIDEO = 0x01;
public final static int STREAM_AUDIO = 0x00;
/** Some app is already using a camera (Camera.open() has failed). */
public final static int ERROR_CAMERA_ALREADY_IN_USE = 0x00;
/** The phone may not support some streaming parameters that you are trying to use (bit rate, frame rate, resolution...). */
public final static int ERROR_CONFIGURATION_NOT_SUPPORTED = 0x01;
/**
* The internal storage of the phone is not ready.
* libstreaming tried to store a test file on the sdcard but couldn't.
* See H264Stream and AACStream to find out why libstreaming would want to something like that.
*/
public final static int ERROR_STORAGE_NOT_READY = 0x02;
/** The phone has no flash. */
public final static int ERROR_CAMERA_HAS_NO_FLASH = 0x03;
/** The supplied SurfaceView is not a valid surface, or has not been created yet. */
public final static int ERROR_INVALID_SURFACE = 0x04;
/**
* The destination set with {#link Session#setDestination(String)} could not be resolved.
* May mean that the phone has no access to the internet, or that the DNS server could not
* resolved the host name.
*/
public final static int ERROR_UNKNOWN_HOST = 0x05;
/**
* Some other error occurred !
*/
public final static int ERROR_OTHER = 0x06;
private String mOrigin;
private String mDestination;
private int mTimeToLive = 64;
private long mTimestamp;
private AudioStream mAudioStream = null;
private VideoStream mVideoStream = null;
private Callback mCallback;
private Handler mMainHandler;
private Handler mHandler;
/**
* Creates a streaming session that can be customized by adding tracks.
*/
public Session() {
long uptime = System.currentTimeMillis();
HandlerThread thread = new HandlerThread("net.majorkernelpanic.streaming.Session");
thread.start();
mHandler = new Handler(thread.getLooper());
mMainHandler = new Handler(Looper.getMainLooper());
mTimestamp = (uptime/1000)<<32 & (((uptime-((uptime/1000)*1000))>>32)/1000); // NTP timestamp
mOrigin = "127.0.0.1";
}
/**
* The callback interface you need to implement to get some feedback
* Those will be called from the UI thread.
*/
public interface Callback {
/**
* Called periodically to inform you on the bandwidth
* consumption of the streams when streaming.
*/
public void onBitrateUpdate(long bitrate);
/** Called when some error occurs. */
public void onSessionError(int reason, int streamType, Exception e);
/**
* Called when the previw of the {#link VideoStream}
* has correctly been started.
* If an error occurs while starting the preview,
* {#link Callback#onSessionError(int, int, Exception)} will be
* called instead of {#link Callback#onPreviewStarted()}.
*/
public void onPreviewStarted();
/**
* Called when the session has correctly been configured
* after calling {#link Session#configure()}.
* If an error occurs while configuring the {#link Session},
* {#link Callback#onSessionError(int, int, Exception)} will be
* called instead of {#link Callback#onSessionConfigured()}.
*/
public void onSessionConfigured();
/**
* Called when the streams of the session have correctly been started.
* If an error occurs while starting the {#link Session},
* {#link Callback#onSessionError(int, int, Exception)} will be
* called instead of {#link Callback#onSessionStarted()}.
*/
public void onSessionStarted();
/** Called when the stream of the session have been stopped. */
public void onSessionStopped();
}
/** You probably don't need to use that directly, use the {#link SessionBuilder}. */
void addAudioTrack(AudioStream track) {
removeAudioTrack();
mAudioStream = track;
}
/** You probably don't need to use that directly, use the {#link SessionBuilder}. */
void addVideoTrack(VideoStream track) {
removeVideoTrack();
mVideoStream = track;
}
/** You probably don't need to use that directly, use the {#link SessionBuilder}. */
void removeAudioTrack() {
if (mAudioStream != null) {
mAudioStream.stop();
mAudioStream = null;
}
}
/** You probably don't need to use that directly, use the {#link SessionBuilder}. */
void removeVideoTrack() {
if (mVideoStream != null) {
mVideoStream.stopPreview();
mVideoStream = null;
}
}
/** Returns the underlying {#link AudioStream} used by the {#link Session}. */
public AudioStream getAudioTrack() {
return mAudioStream;
}
/** Returns the underlying {#link VideoStream} used by the {#link Session}. */
public VideoStream getVideoTrack() {
return mVideoStream;
}
/**
* Sets the callback interface that will be called by the {#link Session}.
* #param callback The implementation of the {#link Callback} interface
*/
public void setCallback(Callback callback) {
mCallback = callback;
}
/**
* The origin address of the session.
* It appears in the session description.
* #param origin The origin address
*/
public void setOrigin(String origin) {
mOrigin = origin;
}
/**
* The destination address for all the streams of the session. <br />
* Changes will be taken into account the next time you start the session.
* #param destination The destination address
*/
public void setDestination(String destination) {
mDestination = destination;
}
/**
* Set the TTL of all packets sent during the session. <br />
* Changes will be taken into account the next time you start the session.
* #param ttl The Time To Live
*/
public void setTimeToLive(int ttl) {
mTimeToLive = ttl;
}
/**
* Sets the configuration of the stream. <br />
* You can call this method at any time and changes will take
* effect next time you call {#link #configure()}.
* #param quality Quality of the stream
*/
public void setVideoQuality(VideoQuality quality) {
if (mVideoStream != null) {
mVideoStream.setVideoQuality(quality);
}
}
/**
* Sets a Surface to show a preview of recorded media (video). <br />
* You can call this method at any time and changes will take
* effect next time you call {#link #start()} or {#link #startPreview()}.
*/
public void setSurfaceView(final SurfaceView view) {
mHandler.post(new Runnable() {
#Override
public void run() {
if (mVideoStream != null) {
mVideoStream.setSurfaceView(view);
}
}
});
}
/**
* Sets the orientation of the preview. <br />
* You can call this method at any time and changes will take
* effect next time you call {#link #configure()}.
* #param orientation The orientation of the preview
*/
public void setPreviewOrientation(int orientation) {
if (mVideoStream != null) {
mVideoStream.setPreviewOrientation(orientation);
}
}
/**
* Sets the configuration of the stream. <br />
* You can call this method at any time and changes will take
* effect next time you call {#link #configure()}.
* #param quality Quality of the stream
*/
public void setAudioQuality(AudioQuality quality) {
if (mAudioStream != null) {
mAudioStream.setAudioQuality(quality);
}
}
/**
* Returns the {#link Callback} interface that was set with
* {#link #setCallback(Callback)} or null if none was set.
*/
public Callback getCallback() {
return mCallback;
}
/**
* Returns a Session Description that can be stored in a file or sent to a client with RTSP.
* #return The Session Description.
* #throws IllegalStateException Thrown when {#link #setDestination(String)} has never been called.
*/
public String getSessionDescription() {
StringBuilder sessionDescription = new StringBuilder();
if (mDestination==null) {
throw new IllegalStateException("setDestination() has not been called !");
}
sessionDescription.append("v=0\r\n");
// TODO: Add IPV6 support
sessionDescription.append("o=- "+mTimestamp+" "+mTimestamp+" IN IP4 "+mOrigin+"\r\n");
sessionDescription.append("s=Unnamed\r\n");
sessionDescription.append("i=N/A\r\n");
sessionDescription.append("c=IN IP4 "+mDestination+"\r\n");
// t=0 0 means the session is permanent (we don't know when it will stop)
sessionDescription.append("t=0 0\r\n");
sessionDescription.append("a=recvonly\r\n");
// Prevents two different sessions from using the same peripheral at the same time
if (mAudioStream != null) {
sessionDescription.append(mAudioStream.getSessionDescription());
sessionDescription.append("a=control:trackID="+0+"\r\n");
}
if (mVideoStream != null) {
sessionDescription.append(mVideoStream.getSessionDescription());
sessionDescription.append("a=control:trackID="+1+"\r\n");
}
return sessionDescription.toString();
}
/** Returns the destination set with {#link #setDestination(String)}. */
public String getDestination() {
return mDestination;
}
/** Returns an approximation of the bandwidth consumed by the session in bit per second. */
public long getBitrate() {
long sum = 0;
if (mAudioStream != null) sum += mAudioStream.getBitrate();
if (mVideoStream != null) sum += mVideoStream.getBitrate();
return sum;
}
/** Indicates if a track is currently running. */
public boolean isStreaming() {
if ( (mAudioStream!=null && mAudioStream.isStreaming()) || (mVideoStream!=null && mVideoStream.isStreaming()) )
return true;
else
return false;
}
/**
* Configures all streams of the session.
**/
public void configure() {
mHandler.post(new Runnable() {
#Override
public void run() {
try {
syncConfigure();
} catch (Exception e) {};
}
});
}
/**
* Does the same thing as {#link #configure()}, but in a synchronous manner. <br />
* Throws exceptions in addition to calling a callback
* {#link Callback#onSessionError(int, int, Exception)} when
* an error occurs.
**/
public void syncConfigure()
throws CameraInUseException,
StorageUnavailableException,
ConfNotSupportedException,
InvalidSurfaceException,
RuntimeException,
IOException {
for (int id=0;id<2;id++) {
Stream stream = id==0 ? mAudioStream : mVideoStream;
if (stream!=null && !stream.isStreaming()) {
try {
stream.configure();
} catch (CameraInUseException e) {
postError(ERROR_CAMERA_ALREADY_IN_USE , id, e);
throw e;
} catch (StorageUnavailableException e) {
postError(ERROR_STORAGE_NOT_READY , id, e);
throw e;
} catch (ConfNotSupportedException e) {
postError(ERROR_CONFIGURATION_NOT_SUPPORTED , id, e);
throw e;
} catch (InvalidSurfaceException e) {
postError(ERROR_INVALID_SURFACE , id, e);
throw e;
} catch (IOException e) {
postError(ERROR_OTHER, id, e);
throw e;
} catch (RuntimeException e) {
postError(ERROR_OTHER, id, e);
throw e;
}
}
}
postSessionConfigured();
}
/**
* Asynchronously starts all streams of the session.
**/
public void start() {
mHandler.post(new Runnable() {
#Override
public void run() {
try {
syncStart();
} catch (Exception e) {}
}
});
}
/**
* Starts a stream in a synchronous manner. <br />
* Throws exceptions in addition to calling a callback.
* #param id The id of the stream to start
**/
public void syncStart(int id)
throws CameraInUseException,
StorageUnavailableException,
ConfNotSupportedException,
InvalidSurfaceException,
UnknownHostException,
IOException {
Stream stream = id==0 ? mAudioStream : mVideoStream;
if (stream!=null && !stream.isStreaming()) {
try {
InetAddress destination = InetAddress.getByName(mDestination);
stream.setTimeToLive(mTimeToLive);
stream.setDestinationAddress(destination);
stream.start();
if (getTrack(1-id) == null || getTrack(1-id).isStreaming()) {
postSessionStarted();
}
if (getTrack(1-id) == null || !getTrack(1-id).isStreaming()) {
mHandler.post(mUpdateBitrate);
}
} catch (UnknownHostException e) {
postError(ERROR_UNKNOWN_HOST, id, e);
throw e;
} catch (CameraInUseException e) {
postError(ERROR_CAMERA_ALREADY_IN_USE , id, e);
throw e;
} catch (StorageUnavailableException e) {
postError(ERROR_STORAGE_NOT_READY , id, e);
throw e;
} catch (ConfNotSupportedException e) {
postError(ERROR_CONFIGURATION_NOT_SUPPORTED , id, e);
throw e;
} catch (InvalidSurfaceException e) {
postError(ERROR_INVALID_SURFACE , id, e);
throw e;
} catch (IOException e) {
postError(ERROR_OTHER, id, e);
throw e;
} catch (RuntimeException e) {
postError(ERROR_OTHER, id, e);
throw e;
}
}
}
/**
* Does the same thing as {#link #start()}, but in a synchronous manner. <br />
* Throws exceptions in addition to calling a callback.
**/
public void syncStart()
throws CameraInUseException,
StorageUnavailableException,
ConfNotSupportedException,
InvalidSurfaceException,
UnknownHostException,
IOException {
syncStart(1);
try {
syncStart(0);
} catch (RuntimeException e) {
syncStop(1);
throw e;
} catch (IOException e) {
syncStop(1);
throw e;
}
}
/** Stops all existing streams. */
public void stop() {
mHandler.post(new Runnable() {
#Override
public void run() {
syncStop();
}
});
}
/**
* Stops one stream in a synchronous manner.
* #param id The id of the stream to stop
**/
private void syncStop(final int id) {
Stream stream = id==0 ? mAudioStream : mVideoStream;
if (stream!=null) {
stream.stop();
}
}
/** Stops all existing streams in a synchronous manner. */
public void syncStop() {
syncStop(0);
syncStop(1);
postSessionStopped();
}
/**
* Asynchronously starts the camera preview. <br />
* You should of course pass a {#link SurfaceView} to {#link #setSurfaceView(SurfaceView)}
* before calling this method. Otherwise, the {#link Callback#onSessionError(int, int, Exception)}
* callback will be called with {#link #ERROR_INVALID_SURFACE}.
*/
public void startPreview() {
mHandler.post(new Runnable() {
#Override
public void run() {
if (mVideoStream != null) {
try {
mVideoStream.startPreview();
postPreviewStarted();
mVideoStream.configure();
} catch (CameraInUseException e) {
postError(ERROR_CAMERA_ALREADY_IN_USE , STREAM_VIDEO, e);
} catch (ConfNotSupportedException e) {
postError(ERROR_CONFIGURATION_NOT_SUPPORTED , STREAM_VIDEO, e);
} catch (InvalidSurfaceException e) {
postError(ERROR_INVALID_SURFACE , STREAM_VIDEO, e);
} catch (RuntimeException e) {
postError(ERROR_OTHER, STREAM_VIDEO, e);
} catch (StorageUnavailableException e) {
postError(ERROR_STORAGE_NOT_READY, STREAM_VIDEO, e);
} catch (IOException e) {
postError(ERROR_OTHER, STREAM_VIDEO, e);
}
}
}
});
}
/**
* Asynchronously stops the camera preview.
*/
public void stopPreview() {
mHandler.post(new Runnable() {
#Override
public void run() {
if (mVideoStream != null) {
mVideoStream.stopPreview();
}
}
});
}
/** Switch between the front facing and the back facing camera of the phone. <br />
* If {#link #startPreview()} has been called, the preview will be briefly interrupted. <br />
* If {#link #start()} has been called, the stream will be briefly interrupted.<br />
* To find out which camera is currently selected, use {#link #getCamera()}
**/
public void switchCamera() {
mHandler.post(new Runnable() {
#Override
public void run() {
if (mVideoStream != null) {
try {
mVideoStream.switchCamera();
postPreviewStarted();
} catch (CameraInUseException e) {
postError(ERROR_CAMERA_ALREADY_IN_USE , STREAM_VIDEO, e);
} catch (ConfNotSupportedException e) {
postError(ERROR_CONFIGURATION_NOT_SUPPORTED , STREAM_VIDEO, e);
} catch (InvalidSurfaceException e) {
postError(ERROR_INVALID_SURFACE , STREAM_VIDEO, e);
} catch (IOException e) {
postError(ERROR_OTHER, STREAM_VIDEO, e);
} catch (RuntimeException e) {
postError(ERROR_OTHER, STREAM_VIDEO, e);
}
}
}
});
}
/**
* Returns the id of the camera currently selected. <br />
* It can be either {#link CameraInfo#CAMERA_FACING_BACK} or
* {#link CameraInfo#CAMERA_FACING_FRONT}.
*/
public int getCamera() {
return mVideoStream != null ? mVideoStream.getCamera() : 0;
}
/**
* Toggles the LED of the phone if it has one.
* You can get the current state of the flash with
* {#link Session#getVideoTrack()} and {#link VideoStream#getFlashState()}.
**/
public void toggleFlash() {
mHandler.post(new Runnable() {
#Override
public void run() {
if (mVideoStream != null) {
try {
mVideoStream.toggleFlash();
} catch (RuntimeException e) {
postError(ERROR_CAMERA_HAS_NO_FLASH, STREAM_VIDEO, e);
}
}
}
});
}
/** Deletes all existing tracks & release associated resources. */
public void release() {
removeAudioTrack();
removeVideoTrack();
mHandler.getLooper().quit();
}
private void postPreviewStarted() {
mMainHandler.post(new Runnable() {
#Override
public void run() {
if (mCallback != null) {
mCallback.onPreviewStarted();
}
}
});
}
private void postSessionConfigured() {
mMainHandler.post(new Runnable() {
#Override
public void run() {
if (mCallback != null) {
mCallback.onSessionConfigured();
}
}
});
}
private void postSessionStarted() {
mMainHandler.post(new Runnable() {
#Override
public void run() {
if (mCallback != null) {
mCallback.onSessionStarted();
}
}
});
}
private void postSessionStopped() {
mMainHandler.post(new Runnable() {
#Override
public void run() {
if (mCallback != null) {
mCallback.onSessionStopped();
}
}
});
}
private void postError(final int reason, final int streamType,final Exception e) {
mMainHandler.post(new Runnable() {
#Override
public void run() {
if (mCallback != null) {
mCallback.onSessionError(reason, streamType, e);
}
}
});
}
private void postBitRate(final long bitrate) {
mMainHandler.post(new Runnable() {
#Override
public void run() {
if (mCallback != null) {
mCallback.onBitrateUpdate(bitrate);
}
}
});
}
private Runnable mUpdateBitrate = new Runnable() {
#Override
public void run() {
if (isStreaming()) {
postBitRate(getBitrate());
mHandler.postDelayed(mUpdateBitrate, 500);
} else {
postBitRate(0);
}
}
};
public boolean trackExists(int id) {
if (id==0)
return mAudioStream!=null;
else
return mVideoStream!=null;
}
public Stream getTrack(int id) {
if (id==0)
return mAudioStream;
else
return mVideoStream;
}
}
Related
I am upgrading a 1.x version log4j product to 2.5
We have a single properties file which holds various configurations. A sample configuration(trace.properties) is as below:
cfg_test.status=debug
cfg_test.appenders=rolling
cfg_test.appender.rolling.type=RollingFile
cfg_test.appender.rolling.name=RollingFile_TEST
cfg_test.appender.rolling.fileName=D:/log/test.log
cfg_test.appender.rolling.filePattern=D:/log/test_%d{MMdd}.log
cfg_test.appender.rolling.layout.type=PatternLayout
cfg_test.appender.rolling.layout.pattern=%d %-5p %m%n
cfg_test.appender.rolling.policies.type = Policies
cfg_test.appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
cfg_test.appender.rolling.policies.time.interval = 1
cfg_test.appender.rolling.policies.time.modulate = true
cfg_test.appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
cfg_test.appender.rolling.policies.size.size=100MB
cfg_test.appender.rolling.strategy.type = DefaultRolloverStrategy
cfg_test.appender.rolling.strategy.max = 5
cfg_test.rootLogger.level=debug
cfg_test.rootLogger.appenderRefs=test
cfg_test.rootLogger.appenderRef.test.ref=RollingFile_TEST
cfg_crp.rootLogger.level=info
cfg_crp.rootLogger.appenderRefs=crp, stdout
cfg_crp.rootLogger.appenderRef.crp.ref=RollingFile_CRP
cfg_crp.rootLogger.appenderRef.stdout.ref=STDOUT
Here cfg_test is a test configuration and cfg_crp is a configuration for a functionality in product which is launched as a separate module.
I have a custom factory as below:
public class TraceFactory {
private static boolean isInitialized = false;
/**
* intializes the trace with the given trace key.
* <p/>
* If if the trace key is null, we will use the console trace
*
* #param traceKey trace key
*/
public static void initialize(String traceKey) {
initPrefix(traceKey != null ? "cfg_" + traceKey + "." : null, PropertiesUtils.readFromClassPath("properties/trace"));
}
private static void initPrefix(String prefix, Properties properties) {
if (isInitialized) {
return;
}
if (prefix == null) {
TraceFactory.initializeAsConsoleTracer();
return;
}
Properties cfg = new Properties();
for (Map.Entry<Object, Object> objectObjectEntry : properties.entrySet()) {
Map.Entry entry = (Map.Entry) objectObjectEntry;
String key = (String) entry.getKey();
String value = (String) entry.getValue();
if (key.startsWith(prefix)) {
cfg.put(key.substring(prefix.length()), value);
}
}
PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory(); // This line and the try catch below replace the
try {
ConfigurationSource configSrc = createConfigurationSource(cfg); //PropertyConfigurator.configure(cfg); from log4j1.2
Configuration conf = factory.getConfiguration(configSrc);
LoggerContext ctx = Configurator.initialize(conf);
ctx.reconfigure();
}
catch (IOException io)
{
}
isInitialized = true;
}
/**
*
* #param cfg the log4j configuration as a properties bundle read from a properties file.
* #return {#link ConfigurationSource} object
* #throws IOException
*/
private static ConfigurationSource createConfigurationSource(Properties cfg) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
cfg.store(out, null);
InputStream in = new ByteArrayInputStream(out.toByteArray());
return new ConfigurationSource(in);
}
public static TraceInterface getTracer(Class class_) {
if (useConsoleTracer) {
return new ConsoleTracer(null);
}
return Log4JTracer.getTracer(class_);
}
public static TraceInterface getTracer(String name) {
if (useConsoleTracer) {
return new ConsoleTracer(null);
}
return Log4JTracer.getTracer(name);
}
}
My LogWrapper Log4JTracer is :-
public class Log4JTracer implements TraceInterface {
private static final String FQCN = Log4JTracer.class.getName();
/**
* extended logger wrapper
*/
private final ExtendedLoggerWrapper log;
private Log4JTracer(final Logger logger) {
this.log = new ExtendedLoggerWrapper((AbstractLogger)logger, logger.getName(), logger.getMessageFactory());
}
/**
* Constructs new logger.
*
* #param name internally used by log4j.
*/
protected Log4JTracer(String name) {
Logger logger = LogManager.getLogger(name);
log = new ExtendedLoggerWrapper((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory());
}
/**
*
* #param clazz
*/
public Log4JTracer(Class<?> clazz)
{
Logger logger = LogManager.getLogger(clazz);
log = new ExtendedLoggerWrapper((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory());
}
/**
* {#inheritDoc}
*/
public void debug(Object message) {
debug(message, null);
}
/**
* {#inheritDoc}
*/
public void debug(Object message, Throwable t) {
log.logIfEnabled(FQCN, Level.DEBUG, null, message, t);
}
/**
* {#inheritDoc}
*/
public void info(Object message) {
info(message, null);
}
/**
* {#inheritDoc}
*/
public void info(Object message, Throwable t) {
log.logIfEnabled(FQCN, Level.INFO, null, message, t);
}
/**
* {#inheritDoc}
*/
public boolean isWarnEnabled() {
return log.isWarnEnabled();
}
/**
* {#inheritDoc}
*/
public void warn(Object message) {
warn(message, null);
}
/**
* {#inheritDoc}
*/
public void warn(Object message, Throwable t) {
log.logIfEnabled(FQCN, Level.WARN, null, message, t);
}
/**
* {#inheritDoc}
*/
public boolean isErrorEnabled() {
return log.isErrorEnabled();
}
/**
* {#inheritDoc}
*/
public void error(Object message) {
error(message, null);
}
/**
* {#inheritDoc}
*/
public void error(Object message, Throwable t) {
log.logIfEnabled(FQCN, Level.ERROR, null, message, t);
}
/**
* {#inheritDoc}
*/
public boolean isFatalEnabled() {
return log.isFatalEnabled();
}
/**
* {#inheritDoc}
*/
public void fatal(Object message, Throwable t) {
log.logIfEnabled(FQCN, Level.FATAL, null, message, t);
}
/**
* {#inheritDoc}
*/
#Override
public boolean isDebugEnabled() {
return log.isDebugEnabled();
}
/**
* {#inheritDoc}
*/
#Override
public boolean isInfoEnabled() {
return log.isInfoEnabled();
}
public static Log4JTracer getTracer(Class cl) {
return new Log4JTracer(cl);
}
public static Log4JTracer getTracer(String name) {
return new Log4JTracer(name);
}
}
Now when I try to use a logger from a class as below, It does not get the logger according to the config:
Public class Test {
Private TraceInterface trace;
Public void execute() {
TraceFactory.initialize("test");
trace = TraceFactory.getTracer();
trace.debug("testing.."); // this never prints. Although a test.log is created with zero size as soon as the TraceFactory.initialize method finshes.
Thanks and Regards,
Tarun
I got it working by doing the following:
Modified the TraceFactory to have :
private LoggerContext ctx;
.....
In method initPrefix
//ctx.reconfigure();
ctx.start(conf);
ContextAnchor.THREAD_CONTEXT.set(ctx);
ctx.updateLoggers();
This is my first question on StackOverflow and I hope I have adhered to the expected standards.
I have been taking over some code from someone else who isn't working here anymore and I'm pretty much stranded here. I searched and asked some colleagues (not too much Java experience unfortunately) but no-one seems to be able to help me. Searching didn't really help me either.
I'm sending Json requests to a Netty server from a client which intentionally is NOT implemented using Netty. For now it is just a simple Java socket, but the intention is to have a Flask client send requests to the Netty server. The requests arrive (both using Java Sockets and using Python Flask), and get properly processed in the pipeline, but I want to send a response to the client and although I suspect where in the code to send the response I'm clearly missing out on something as I don't get any response. Any suggestions?
The Java Socket client (note that the json1 and json2 strings have been omitted from the snippet here as they are rather long, but they are formatted properly). Posting requests using a Socket and the related output stream. The response part (with the input stream for the same socket) is just some test which I have my doubt about, but not sure how to do this otherwise (and that's why I kept it here). I've been seeing plenty of examples with clients implementing Netty interfaces and that seems to work fine, but as said I want a client not using Netty to be able to receive the responses as well (if that's possible at all).
String serverResponse;
for (int j = 0; j < 100; j++) {
for (int i = 0; i < 1000; i++) {
try {
Socket s = new Socket("localhost", 12000);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.write(json1 + i + json2);
out.flush();
// Testing only - trying to get the response back from the server
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
while(true) {
if ((serverResponse = in.readLine()) != null) {
log.info("server says", serverResponse);
break;
}
}
out.close();
s.close();
Thread.sleep(1000);
} catch (Exception ex) {
ex.printStackTrace();
}
}
Thread.sleep(2000);
}
MCTcpServer.java
/**
* Abstract TCP Server class. this class should be implemented in the subclass to implement an actual server.
*
* #param <R> The data to be read from the socket.
* #param <W> data to be written (in case of duplex) from the socket.
*/
public abstract class MFTcpServer<R, W> {
protected final AtomicBoolean started;
protected MFTcpServer() {
this.started = new AtomicBoolean();
}
/**
* Start the server.
*
* #param initializer the channel initializers. they will be called when a new client connects to the server.
* #return instance of tcp server
*/
public final MFTcpServer<R, W> start(ChannelInitializer<Channel> initializer) {
if (!started.compareAndSet(false, true)) {
throw new IllegalStateException("Server already started");
}
doStart(initializer);
return this;
}
/**
* Start the server and wait for all the threads to be finished before shutdown.
* #param initializer the channel initializers. they will be called when a new client connects to the server.
*/
public final void startAndAwait(ChannelInitializer<Channel> initializer) {
start(initializer);
awaitShutdown();
}
/**
* Shutdown the server
* #return true if successfully shutdown.
*/
public final boolean shutdown() {
return !started.compareAndSet(true, false) || doShutdown();
}
/**
* Wait for all the threads to be finished before shutdown.
*/
public abstract void awaitShutdown();
/**
* Do the shutdown now.
* #return true if successfully shutdown
*/
public abstract boolean doShutdown();
/**
* start the server
* #param initializer the channel initializers. they will be called when a new client connetcs to the server.
* #return instance of tcp server
*/
public abstract MFTcpServer<R, W> doStart(ChannelInitializer<Channel> initializer);
/**
*
* #return the port where the server is running.
*/
public abstract int getPort();
MFNetty4TcpServer.java Actual server implementation
public class MFNetty4TcpServer<R, W> extends MFTcpServer<R, W> {
private static final Logger logger = LoggerFactory.getLogger(MFNetty4TcpServer.class);
private static final int BOSS_THREAD_POOL_SIZE = 2;
private int port;
private ServerBootstrap bootstrap;
private ChannelFuture bindFuture;
/**
* The constructor.
*
* #param port port where to listen
*/
protected MFNetty4TcpServer(int port) {
this.port = port;
final NioEventLoopGroup bossGroup = new NioEventLoopGroup(0, new DefaultEventExecutorGroup
(BOSS_THREAD_POOL_SIZE));
final NioEventLoopGroup workerGroup = new NioEventLoopGroup(0, new DefaultEventExecutorGroup
(JsonProducerConfig.THREAD_POOL_SIZE));
bootstrap = new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class);
}
#Override
public MFNetty4TcpServer<R, W> doStart(ChannelInitializer<Channel> initializer) {
bootstrap.childHandler(new ChannelInitializer<Channel>() {
#Override
protected void initChannel(Channel ch) throws Exception {
if (initializer != null) {
ch.pipeline().addLast(initializer);
}
}
});
try {
bindFuture = bootstrap.bind(port).sync();
if (!bindFuture.isSuccess()) {
// Connection not successful
throw new RuntimeException(bindFuture.cause());
}
SocketAddress localAddress = bindFuture.channel().localAddress();
if (localAddress instanceof InetSocketAddress) {
port = ((InetSocketAddress) localAddress).getPort();
logger.info("Started server at port: " + port);
}
} catch (InterruptedException e) {
logger.error("Error waiting for binding server port: " + port, e);
}
return this;
}
#Override
public void awaitShutdown() {
try {
bindFuture.channel().closeFuture().await();
} catch (InterruptedException e) {
Thread.interrupted(); // Reset the interrupted status
logger.error("Interrupted while waiting for the server socket to close.", e);
}
}
#Override
public boolean doShutdown() {
try {
bindFuture.channel().close().sync();
return true;
} catch (InterruptedException e) {
logger.error("Failed to shutdown the server.", e);
return false;
}
}
#Override
public int getPort() {
return port;
}
/**
* Creates a tcp server at the defined port.
*
* #param port port to listen to
* #param <R> data to be read
* #param <W> data to be written back. Only in case of duplex connection.
* #return instance of tcp server.
*/
public static <R, W> MFTcpServer<R, W> create(int port) {
return new MFNetty4TcpServer<>(port);
}
}
JsonProducerConfig.java The pipeline is setup here.
/**
* Spring Configuration class of the application.
*/
#Configuration
#Import({DatabusConfig.class})
public class JsonProducerConfig {
private static final Logger log = LoggerFactory.getLogger(JsonProducerConfig.class);
public static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
public static final String TCP_SERVER = "tcpServer";
public static final String CHANNEL_PIPELINE_INITIALIZER = "channel_initializer";
public static final String MF_KAFKA_PRODUCER = "mf_kafka_producer";
public static final String JSON_AVRO_CONVERTOR = "jsonAvroConvertor";
#Value("#{systemProperties['tcpserver.port']?:'12000'}")
private String tcpServerPort;
#Bean(name = TCP_SERVER)
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public MFTcpServer nettyTCPServer() {
return MFNetty4TcpServer.create(Integer.parseInt(tcpServerPort));
}
#Bean(name = MF_KAFKA_PRODUCER)
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public MFKafkaProducer pushToKafka() {
return new MFKafkaProducer();
}
#Bean(name = JSON_AVRO_CONVERTOR)
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public JsonAvroConvertor jsonAvroConvertor() {
return new JsonAvroConvertor();
}
/**
* This is where the pipeline is set for processing of events.
*
* #param jsonAvroConvertor converts json to avro
* #param kafkaProducer pushes to kafka
* #return chanenl initializers pipeline.
*/
#Bean(name = CHANNEL_PIPELINE_INITIALIZER)
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public ChannelInitializer<Channel> channelInitializers(JsonAvroConvertor jsonAvroConvertor,
MFKafkaProducer kafkaProducer) {
return new ChannelInitializer<Channel>() {
#Override
protected void initChannel(Channel channel) throws Exception {
if (log.isInfoEnabled())
log.info("initChannel - initing channel...");
channel.pipeline().addLast(new NioEventLoopGroup(0, new DefaultEventExecutorGroup(THREAD_POOL_SIZE)));
channel.pipeline().addLast(new JsonObjectDecoder(1048576));
channel.pipeline().addLast(jsonAvroConvertor);
channel.pipeline().addLast(kafkaProducer);
if (log.isInfoEnabled())
log.info("channel = " + channel.toString());
}
};
}
}
JsonProducer.java The main program
public class JsonProducer {
private static final Logger log = LoggerFactory.getLogger(JsonProducer.class);
private static MFTcpServer tcpServer;
/**
* Main startup method
*
* #param args not used
*/
public static void main(String[] args) {
System.setProperty("solschema", "false");
try {
// the shutdown hook.
Runtime.getRuntime().addShutdownHook(new Thread(
() -> {
if (tcpServer != null) {
tcpServer.shutdown();
}
}
));
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(JsonProducerConfig.class);
tcpServer = (MFTcpServer) context.getBean(JsonProducerConfig.TCP_SERVER);
ChannelInitializer<Channel> channelInitializer = (ChannelInitializer<Channel>) context.
getBean(JsonProducerConfig.CHANNEL_PIPELINE_INITIALIZER);
tcpServer.startAndAwait(channelInitializer);
} catch (Exception t) {
log.error("Error while starting JsonProducer ", t);
System.exit(-1);
}
}
}
The MFKafkaProducer.java as the last channel in the pipeline. Note the ctx.writeAndFlush(msg) in the channelRead method which is where I understand the response should be initiated. But what after that. When running this channelFuture.isSuccess() evaluates to false. The response object was an attempt to a String response.
#ChannelHandler.Sharable
public class MFKafkaProducer extends ChannelInboundHandlerAdapter {
private static final Logger log = LoggerFactory.getLogger(MFKafkaProducer.class);
#Resource
ApplicationContext context;
#Resource(name = DatabusConfig.ADMIN)
Admin admin;
private Map<String, IProducer> streams = new HashMap<>();
#PreDestroy
public void stop() {
removeAllStreams(); // then stop writing to producers
}
/**
* #param clickRecord the record to be pushed to kafka
* #throws Exception
*/
public void handle(GenericRecord clickRecord) throws Exception {
Utf8 clientId = null;
try {
clientId = (Utf8) clickRecord.get(SchemaUtil.APP_ID);
stream(producer(clientId.toString()), clickRecord);
} catch (Exception e) {
String message = "Could not push click data for clientId:" + clientId;
log.warn("handle - " + message + "!!!", e);
assert clientId != null;
removeStream(clientId.toString());
}
}
/**
* removes all the streams
*/
private void removeAllStreams() {
Set<String> strings = streams.keySet();
for (String clientId : strings) {
removeStream(clientId);
}
}
/**
* removes a particular stream
*
* #param clientId the stream to be removed
*/
private void removeStream(String clientId) {
Assert.notEmpty(streams);
IProducer producer = streams.get(clientId);
producer.stopProducer();
streams.remove(clientId);
}
/**
* #param producer the producer where data needs to be written
* #param clickRecord teh record to be written
*/
private void stream(IProducer producer, GenericRecord clickRecord) {
producer.send(clickRecord);
}
/**
* This will create a producer in case it is not already created.
* If already created return the already present one
*
* #param clientId stream id
* #return the producer instance
*/
private IProducer producer(String clientId) {
if (streams.containsKey(clientId)) {
return streams.get(clientId);
} else {
IProducer producer = admin.createKeyTopicProducer(SchemaUtil.APP_ID, "test_" + clientId, new ICallback() {
#Override
public void onSuccess(long offset) {
if (log.isInfoEnabled())
log.info("onSuccess - Data at offset:" + offset + " send.");
}
#Override
public void onError(long offset, Exception ex) {
if (log.isInfoEnabled())
log.info("onError - Data at offset:" + offset + " failed. Exception: ", ex);
}
#Override
public void onStreamClosed() {
log.warn("onStreamClosed - Stream:" + clientId + " closed.");
removeStream(clientId);
}
});
producer.startProducer();
streams.put(clientId, producer);
return producer;
}
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
log.debug("KafkaProducer - channelRead() called with " + "ctx = [" + ctx + "], msg = [" + msg + "]");
if (msg instanceof GenericRecord) {
GenericRecord genericRecord = (GenericRecord) msg;
try {
handle(genericRecord);
log.debug("channelRead sending response");
Charset charset = Charset.defaultCharset();
ByteBuf response = Unpooled.copiedBuffer("Just a response", charset);
ChannelFuture future = ctx.writeAndFlush(msg);
future.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if (channelFuture.isSuccess())
log.info("channelRead - future.operationComplete - Response has been delivered to all channels");
else
log.info("channelRead - future.operationComplete - Response has NOT been delivered to all channels");
}
});
} catch (Exception ex) {
log.error("Something went wrong processing the generic record: " + msg + "\n ", ex);
}
} else {
log.debug("KafkaProducer - msg not of Type Generic Record !!! " + msg);
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
log.error("Something went wrong writing to Kafka: \n", cause);
ctx.close();
}
}
Using ChannelFuture#cause() I noticed I was not serializing a ByteBuf object, but a GenericRecord instead. Using
ByteBuf response = Unpooled.copiedBuffer(genericRecord.toString(), charset);
ChannelFuture future = ctx.writeAndFlush(response);
the GenericRecord gets converted to a ButeBuf and sends a response using the writeAndFlush method.
The test client using a Socket implementation somehow never really received a response, but by using a SocketChannel this was resolved as well.
My problem is that, at random times when several channels are connected to my game, there will be a disconnection causing all of the channels to be closed. The channelDisconnected method is called, and I've done a stacktrace printout of this occurrence and everything seems normal. My code is below; what is the problem?
public final class ServerChannelHandler extends SimpleChannelHandler {
private static ChannelGroup channels;
private static ServerBootstrap bootstrap;
public static final void init() {
new ServerChannelHandler();
}
/**
* Gets the amount of channels that are currently connected to us
* #return A {#code Integer} {#code Object}
*/
public static int getConnectedChannelsSize() {
return channels == null ? 0 : channels.size();
}
/**
* Creates a new private constructor of this class
*/
private ServerChannelHandler() {
channels = new DefaultChannelGroup();
bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(CoresManager.serverBossChannelExecutor, CoresManager.serverWorkerChannelExecutor, CoresManager.serverWorkersCount));
bootstrap.getPipeline().addLast("handler", this);
bootstrap.setOption("reuseAddress", true); // reuses adress for bind
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.TcpAckFrequency", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.bind(new InetSocketAddress(Constants.PORT_ID));
}
/**
* What happens when a new channel is open and connects to us
*/
#Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
channels.add(e.getChannel());
}
/**
* What happens when an open channel closes the connection with us
*/
#Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
channels.remove(e.getChannel());
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
ctx.setAttachment(new Session(e.getChannel()));
}
#Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
Object sessionObject = ctx.getAttachment();
if (sessionObject != null && sessionObject instanceof Session) {
Session session = (Session) sessionObject;
if (session.getDecoder() == null)
return;
if (session.getDecoder() instanceof WorldPacketsDecoder) {
session.getWorldPackets().getPlayer().finish();
}
}
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
if (!(e.getMessage() instanceof ChannelBuffer))
return;
Object sessionObject = ctx.getAttachment();
if (sessionObject != null && sessionObject instanceof Session) {
Session session = (Session) sessionObject;
if (session.getDecoder() == null)
return;
ChannelBuffer buf = (ChannelBuffer) e.getMessage();
buf.markReaderIndex();
int avail = buf.readableBytes();
if (avail < 1 || avail > Constants.RECEIVE_DATA_LIMIT) {
return;
}
byte[] buffer = new byte[avail];
buf.readBytes(buffer);
try {
session.getDecoder().decode(new InputStream(buffer));
} catch (Throwable er) {
er.printStackTrace();
}
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ee) throws Exception {
ee.getCause().printStackTrace();
}
/**
* On server shutdown, all channels are closed and the external resources
* are released from the {{#link #bootstrap}
*/
public static final void shutdown() {
channels.close().awaitUninterruptibly();
bootstrap.releaseExternalResources();
}
}
StackTrace:
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1364)
at com.sallesy.game.player.Player.realFinish(Player.java:854)
at com.sallesy.game.player.Player.finish(Player.java:848)
at com.sallesy.game.player.Player.finish(Player.java:815)
at com.sallesy.networking.ServerChannelHandler.channelDisconnected(ServerChannelHandler.java:71)
at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:120)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:558)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:553)
at org.jboss.netty.channel.Channels.fireChannelDisconnected(Channels.java:399)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.close(AbstractNioWorker.java:721)
at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.handleAcceptedSocket(NioServerSocketPipelineSink.java:111)
at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.eventSunk(NioServerSocketPipelineSink.java:66)
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendDownstream(DefaultChannelPipeline.java:774)
at org.jboss.netty.channel.SimpleChannelHandler.closeRequested(SimpleChannelHandler.java:338)
at org.jboss.netty.channel.SimpleChannelHandler.handleDownstream(SimpleChannelHandler.java:260)
at org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:585)
at org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(DefaultChannelPipeline.java:576)
at org.jboss.netty.channel.Channels.close(Channels.java:820)
at org.jboss.netty.channel.AbstractChannel.close(AbstractChannel.java:197)
at org.jboss.netty.channel.ChannelFutureListener$1.operationComplete(ChannelFutureListener.java:41)
at org.jboss.netty.channel.DefaultChannelFuture.notifyListener(DefaultChannelFuture.java:428)
at org.jboss.netty.channel.DefaultChannelFuture.addListener(DefaultChannelFuture.java:145)
at com.sallesy.networking.encoders.WorldPacketsEncoder.sendLogout(WorldPacketsEncoder.java:1179)
at com.sallesy.game.player.Player.logout(Player.java:801)
at com.sallesy.networking.decoders.handlers.ButtonHandler.handleButtons(ButtonHandler.java:227)
at com.sallesy.networking.decoders.WorldPacketsDecoder.processPackets(WorldPacketsDecoder.java:1122)
at com.sallesy.networking.decoders.WorldPacketsDecoder.decode(WorldPacketsDecoder.java:297)
at com.sallesy.networking.ServerChannelHandler.messageReceived(ServerChannelHandler.java:100)
at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:558)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:553)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:84)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.processSelectedKeys(AbstractNioWorker.java:471)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:332)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:35)
at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:102)
at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Bit of a guess really but could be keepalive timeouts.
You could try using an IdleStateHandler to keep connections alive.
I have a very simple crawler. I want to make my current code run in a few threads. Could you provide me a little tutorial or article to help me achive this test?
I'm originally a .Net developer and in .Net I have no problem whatsoever running codes in multithread but unfortunately I don't know anything about threads in Java.
My crawler is a command-line software so don't worry about GUI.
Thank you in advance.
Java does multithreading through the Thread class. One of the most common ways to make existing code multithreaded is to use the Runnable interface to define what you want to call at thread start, and then start it off.
public class SomeFunctions
{
public static void FunctionA() {}
public static void FunctionB() {}
public static void FunctionC() {}
}
// ...
Thread t1 = new Thread(new Runnable() {
public void run() {
SomeFunctions.FunctionA();
}
});
t1.start();
// (rinse and repeat for the other functions)
Dry coded, but it should at least get the general concept across. Of course, as soon as you go into multithreading land, you have concurrency issues and need to make sure everything is appropriately syhchronized, etc., but any language will have those issues.
If you're worried about synchronization, you have a few tools at your disposal. The easiest is the recursive mutex functionality built into Java, the "synchronized" keyword. More classical means are also available through various classes in the java.util.concurrent and java.util.concurrent.locks packages such as Semaphore and ReadWriteLock
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/package-summary.html
You can take a look at my webcrawler example. Sry for the lengthiness.
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* A web crawler with a Worker pool
*
* #author Adriaan
*/
public class WebCrawler implements Manager {
private Set<Worker> workers = new HashSet<Worker>();
private List<String> toCrawl = new ArrayList<String>();
private Set<String> crawled = new HashSet<String>();
private Set<String> hosts = new HashSet<String>();
private Set<String> results = new HashSet<String>();
private int maxResults;
public WebCrawler(String url, int numberOfWorkers, int maxResults) {
this.maxResults = maxResults;
toCrawl.add(url);
createWorkers(numberOfWorkers);
}
public void createWorkers(int numberOfWorkers) {
for (int i = 0; i < numberOfWorkers; i++) {
workers.add(new Worker(this));
}
}
private void stopWorkers() {
for (Worker worker : workers) {
worker.terminate();
}
}
public synchronized Job getNewJob() {
while (toCrawl.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
// ignore
}
}
return new EmailAddressCrawlJob().setDescription(toCrawl.remove(0));
}
public synchronized void jobCompleted(Job job) {
// System.out.println("crawled: " + job.getDescription());
crawled.add(job.getDescription());
String host = getHost(job.getDescription());
boolean knownHost = hosts.contains(host);
if (!knownHost) {
System.out.println("host: " + host);
hosts.add(host);
}
for (String url : job.getNewDescriptions()) {
if (!crawled.contains(url)) {
if (knownHost) {
toCrawl.add(toCrawl.size() - 1, url);
} else {
toCrawl.add(url);
}
}
}
for (String result : job.getResults()) {
if (results.add(result)) {
System.out.println("result: " + result);
}
}
notifyAll();
if (results.size() >= maxResults) {
stopWorkers();
System.out.println("Crawled hosts:");
for (String crawledHost : hosts) {
System.out.println(crawledHost);
}
Set<String> uncrawledHosts = new HashSet<String>();
for (String toCrawlUrl : toCrawl) {
uncrawledHosts.add(getHost(toCrawlUrl));
}
System.out.println("Uncrawled hosts:");
for (String unCrawledHost : uncrawledHosts) {
System.out.println(unCrawledHost);
}
}
if (crawled.size() % 10 == 0) {
System.out.println("crawled=" + crawled.size() + " toCrawl="
+ toCrawl.size() + " results=" + results.size() + " hosts="
+ hosts.size() + " lastHost=" + host);
}
}
public String getHost(String host) {
int hostStart = host.indexOf("://") + 3;
if (hostStart > 0) {
int hostEnd = host.indexOf("/", hostStart);
if (hostEnd < 0) {
hostEnd = host.length();
}
host = host.substring(hostStart, hostEnd);
}
return host;
}
public static void main(String[] args) throws MalformedURLException {
new WebCrawler("http://www.nu.nl/", 5, 20);
}
}
Worker
**
* A Worker proactively gets a Job, executes it and notifies its manager that
* the Job is completed.
*
* #author Adriaan
*/
public class Worker extends Thread {
private final Manager manager;
private Job job = null;
private boolean isWorking;
public Worker(Manager manager) {
this.manager = manager;
isWorking = true;
start();
}
#Override
public void run() {
System.out.println("Worker " + Thread.currentThread().getId()
+ " starting ");
while (isWorking) {
job = manager.getNewJob();
job.execute();
manager.jobCompleted(job);
}
}
public void terminate() {
isWorking = false;
}
}
Manager interface
/**
* Manager interface for Workers
*
* #author Adriaan
*/
public interface Manager {
/**
* Gets a new job
*
* #return
*/
public Job getNewJob();
/**
* Indicates the job is completed
*
* #param job
*/
public void jobCompleted(Job job);
}
Job
import java.util.HashSet;
import java.util.Set;
/**
* A Job is a unit of work defined by a String (the description). During execution the
* job can obtain results and new job descriptions.
*
* #author Adriaan
*/
public abstract class Job {
private String description;
private Set<String> results = new HashSet<String>();
private Set<String> newDescriptions = new HashSet<String>();
/**
* Sets the job description
*
* #param description
* #return this for chaining
*/
public Job setDescription(String description) {
this.description = description;
return this;
}
/**
* Executes the job
*/
public abstract void execute();
/**
* Gets the results obtained
*
* #return
*/
public Set<String> getResults() {
return results;
}
/**
* Gets the now job descriptions obtained
*
* #return
*/
public Set<String> getNewDescriptions() {
return newDescriptions;
}
/**
* Gets the job description
*
* #return
*/
public String getDescription() {
return description;
}
/**
* Allows the implementation to add an obtained result
*
* #param result
*/
void addResult(String result) {
results.add(result);
}
/**
* Allows the implementation to add an obtained description
*
* #param result
*/
void addNewDescription(String newDescription) {
newDescriptions.add(newDescription);
}
}
A Job which crawls a page for email addresses:
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A Job which crawls HTTP or HTTPS URL's for email adresses, collecting new
* URL's to crawl along the way.
*
* #author Adriaan
*/
public class EmailAddressCrawlJob extends Job {
#Override
public void execute() {
try {
URL url = new URL(getDescription());
if (url != null) {
String text = readText(url);
extractNewDescriptions(text, url);
extractResults(text);
}
} catch (MalformedURLException e) {
System.err.println("Bad url " + getDescription());
}
}
private String readText(URL url) {
URLConnection connection;
try {
connection = url.openConnection();
InputStream input = connection.getInputStream();
byte[] buffer = new byte[1000];
int num = input.read(buffer);
if (num > 0) {
StringBuilder builder = new StringBuilder();
builder.append(new String(buffer, 0, num));
while (num != -1) {
num = input.read(buffer);
if (num != -1) {
builder.append(new String(buffer, 0, num));
}
}
return builder.toString();
}
} catch (IOException e) {
//System.err.println("Could not read from " + url);
}
return "";
}
private void extractNewDescriptions(String text, URL url) {
// URL extracting code from Sun example
String lowerCaseContent = text.toLowerCase();
int index = 0;
while ((index = lowerCaseContent.indexOf("<a", index)) != -1) {
if ((index = lowerCaseContent.indexOf("href", index)) == -1) {
break;
}
if ((index = lowerCaseContent.indexOf("=", index)) == -1) {
break;
}
index++;
String remaining = text.substring(index);
StringTokenizer st = new StringTokenizer(remaining, "\t\n\r\">#");
String strLink = st.nextToken();
if (strLink.startsWith("javascript:")) {
continue;
}
URL urlLink;
try {
urlLink = new URL(url, strLink);
strLink = urlLink.toString();
} catch (MalformedURLException e) {
// System.err.println("Could not create url: " + target
// + " + " + strLink);
continue;
}
// only look at http links
String protocol = urlLink.getProtocol();
if (protocol.compareTo("http") != 0
&& protocol.compareTo("https") != 0) {
// System.err.println("Ignoring: " + protocol
// + " protocol in " + urlLink);
continue;
}
addNewDescription(urlLink.toString());
}
}
private void extractResults(String text) {
Pattern p = Pattern
.compile("([\\w\\-]([\\.\\w])+[\\w]+#([\\w\\-]+\\.)+[A-Za-z]{2,4})");
Matcher m = p.matcher(text);
while (m.find()) {
addResult(m.group(1));
}
}
}
I know this answer is a bit verbose, but I thought OP might be best helped with a working example and I happened to have made one not so long ago.
A very basic java program that will give the abstract idea of the Multi Threading..
public class MyThread extends Thread {
String word;
public MyThread(String rm){
word = rm;
}
public void run(){
try {
for(;;){
System.out.println(word);
Thread.sleep(1000);
}
} catch(InterruptedException e) {
System.out.println("sleep interrupted");
}
}
public static void main(String[] args) {
Thread t1=new MyThread("First Thread");
Thread t2=new MyThread("Second Thread");
t1.start();
t2.start();
}
}
And the Output will be..
First Thread
Second Thread
First Thread
Second Thread
First Thread
Go with this PPT it will help you with the basics..
Here
Is it possible to send sms from windows machine to mobile phone.
I have searched a lot and got the following code.
Sender.java
package sms;
import java.util.Date;
public class Sender implements Runnable {
private static final long STANDARD=500;
private static final long LONG=2000;
private static final long VERYLONG=20000;
SerialConnection mySerial =null;
static final private char cntrlZ=(char)26;
String in, out;
Thread aThread=null;
private long delay=STANDARD;
String recipient=null;
String message=null;
private String csca="+6596845999"; // the message center
private SerialParameters defaultParameters= new SerialParameters ("COM2",9600,0,0,8,1,0);
public int step;
public int status=-1;
public long messageNo=-1;
public Sender(String recipient, String message){
this.recipient=recipient;
this.message=message;
}
/**
* connect to the port and start the dialogue thread
*/
public int send () throws Exception{
SerialParameters params = defaultParameters;
mySerial =new SerialConnection (params);
mySerial.openConnection();
aThread=new Thread(this);
aThread.start() ;
//log("start");
return 0;
}
/**
* implement the dialogue thread,
* message / response via steps,
* handle time out
*/
public void run(){
boolean timeOut=false;
long startTime=(new Date()).getTime();
while ((step <7) && (!timeOut)){
// log(""+((new Date()).getTime() - startTime);
//check where we are in specified delay
timeOut=((new Date()).getTime() - startTime)>delay;
//if atz does not work, type to send cntrlZ and retry, in case a message was stuck
if (timeOut && (step==1)) {
step=-1;
mySerial.send( ""+cntrlZ);
}
//read incoming string
String result= mySerial.getIncommingString() ;
// log ("<- "+result+"\n--------");
int expectedResult=-1;
try{
//log ("Step:"+step);
switch (step){
case 0:
mySerial.send("atz");
delay=LONG;
startTime=(new Date()).getTime();
break;
case 1:
delay=STANDARD;
mySerial.send("ath0");
startTime=(new Date()).getTime();
break;
case 2:
expectedResult=result.indexOf("OK");
//log ("received ok ="+expectedResult);
if (expectedResult>-1){
mySerial.send("at+cmgf=1");
startTime=(new Date()).getTime();
}else{
step=step-1;
}
break;
case 3:
expectedResult=result.indexOf("OK");
// log ("received ok ="+expectedResult);
if (expectedResult>-1){
mySerial.send("at+csca=\""+csca+"\"");
startTime=(new Date()).getTime();
}else{
step=step-1;
}
break;
case 4:
expectedResult=result.indexOf("OK");
// log ("received ok ="+expectedResult);
if (expectedResult>-1){
mySerial.send("at+cmgs=\""+recipient+"\"");
startTime=(new Date()).getTime();
}else{
step=step-1;
}
break;
case 5:
expectedResult=result.indexOf(">");
// log ("received ok ="+expectedResult);
if (expectedResult>-1){
mySerial.send(message+cntrlZ);
startTime=(new Date()).getTime();
}else{
step=step-1;
}
delay=VERYLONG;//waitning for message ack
break;
case 6:
expectedResult=result.indexOf("OK");
//read message number
if (expectedResult>-1){
int n=result.indexOf("CMGS:");
result=result.substring(n+5);
n=result.indexOf("\n");
status=0;
messageNo=Long.parseLong(result.substring(0,n).trim() );
log ("sent message no:"+messageNo);
}else{
step=step-1;
}
break;
}
step=step+1;
aThread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
mySerial.closeConnection() ;
//if timed out set status
if (timeOut ) {
status=-2;
log("*** time out at step "+step+"***");
}
}
/**
* logging function, includes date and class name
*/
private void log(String s){
System.out.println (new java.util.Date()+":"+this.getClass().getName()+":"+s);
}
}
SerialConnection.java
package sms;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TooManyListenersException;
import javax.comm.CommPortIdentifier;
import javax.comm.CommPortOwnershipListener;
import javax.comm.NoSuchPortException;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.comm.UnsupportedCommOperationException;
/**
A class that handles the details of a serial connection. Reads from one
TextArea and writes to a second TextArea.
Holds the state of the connection.
*/
public class SerialConnection implements SerialPortEventListener,
CommPortOwnershipListener {
private SerialParameters parameters;
private OutputStream os;
private InputStream is;
private KeyHandler keyHandler;
private CommPortIdentifier portId;
private SerialPort sPort;
private boolean open;
private String receptionString="";
public String getIncommingString(){
byte[] bVal= receptionString.getBytes();
receptionString="";
return new String (bVal);
}
public SerialConnection(SerialParameters parameters) {
this.parameters = parameters;
open = false;
}
/**
Attempts to open a serial connection and streams using the parameters
in the SerialParameters object. If it is unsuccesfull at any step it
returns the port to a closed state, throws a
<code>SerialConnectionException</code>, and returns.
Gives a timeout of 30 seconds on the portOpen to allow other applications
to reliquish the port if have it open and no longer need it.
*/
public void openConnection() throws SerialConnectionException {
// System.out.println("OK 0 ");
// Obtain a CommPortIdentifier object for the port you want to open.
try {
// System.out.println(parameters.getPortName());
portId = CommPortIdentifier.getPortIdentifier(parameters.getPortName());
} catch (NoSuchPortException e) {
// System.out.println("Yes the problem is here 1 ");
e.printStackTrace();
// throw new SerialConnectionException(e.getMessage());
}catch(Exception e)
{
// System.out.println("ErrorErrorErrorError");
e.printStackTrace();
}
//System.out.println(portId);
//System.out.println("OK 1 ");
// Open the port represented by the CommPortIdentifier object. Give
// the open call a relatively long timeout of 30 seconds to allow
// a different application to reliquish the port if the user
// wants to.
try {
sPort = (SerialPort)portId.open("SMSConnector", 30000);
} catch (PortInUseException e) {
throw new SerialConnectionException(e.getMessage());
}
//System.out.println("OK 2 ");
sPort.sendBreak(1000);
// Set the parameters of the connection. If they won't set, close the
// port before throwing an exception.
try {
setConnectionParameters();
} catch (SerialConnectionException e) {
sPort.close();
throw e;
}
// System.out.println("OK 3 ");
// Open the input and output streams for the connection. If they won't
// open, close the port before throwing an exception.
try {
os = sPort.getOutputStream();
is = sPort.getInputStream();
} catch (IOException e) {
sPort.close();
throw new SerialConnectionException("Error opening i/o streams");
}
//System.out.println("OK 4 ");
/*
// Create a new KeyHandler to respond to key strokes in the
// messageAreaOut. Add the KeyHandler as a keyListener to the
// messageAreaOut.
keyHandler = new KeyHandler(os);
messageAreaOut.addKeyListener(keyHandler);
*/
// Add this object as an event listener for the serial port.
try {
sPort.addEventListener(this);
} catch (TooManyListenersException e) {
sPort.close();
throw new SerialConnectionException("too many listeners added");
}
//System.out.println("OK 5 ");
// Set notifyOnDataAvailable to true to allow event driven input.
sPort.notifyOnDataAvailable(true);
// Set notifyOnBreakInterrup to allow event driven break handling.
sPort.notifyOnBreakInterrupt(true);
// Set receive timeout to allow breaking out of polling loop during
// input handling.
try {
sPort.enableReceiveTimeout(30);
} catch (UnsupportedCommOperationException e) {
}
//System.out.println("OK 6 ");
// Add ownership listener to allow ownership event handling.
portId.addPortOwnershipListener(this);
open = true;
}
/**
Sets the connection parameters to the setting in the parameters object.
If set fails return the parameters object to origional settings and
throw exception.
*/
public void setConnectionParameters() throws SerialConnectionException {
// Save state of parameters before trying a set.
int oldBaudRate = sPort.getBaudRate();
int oldDatabits = sPort.getDataBits();
int oldStopbits = sPort.getStopBits();
int oldParity = sPort.getParity();
int oldFlowControl = sPort.getFlowControlMode();
// Set connection parameters, if set fails return parameters object
// to original state.
try {
sPort.setSerialPortParams(parameters.getBaudRate(),
parameters.getDatabits(),
parameters.getStopbits(),
parameters.getParity());
} catch (UnsupportedCommOperationException e) {
parameters.setBaudRate(oldBaudRate);
parameters.setDatabits(oldDatabits);
parameters.setStopbits(oldStopbits);
parameters.setParity(oldParity);
throw new SerialConnectionException("Unsupported parameter");
}
// Set flow control.
try {
sPort.setFlowControlMode(parameters.getFlowControlIn()
| parameters.getFlowControlOut());
} catch (UnsupportedCommOperationException e) {
throw new SerialConnectionException("Unsupported flow control");
}
}
/**
Close the port and clean up associated elements.
*/
public void closeConnection() {
// If port is alread closed just return.
if (!open) {
return;
}
// Remove the key listener.
// messageAreaOut.removeKeyListener(keyHandler);
// Check to make sure sPort has reference to avoid a NPE.
if (sPort != null) {
try {
// close the i/o streams.
os.close();
is.close();
} catch (IOException e) {
System.err.println(e);
}
// Close the port.
sPort.close();
// Remove the ownership listener.
portId.removePortOwnershipListener(this);
}
open = false;
}
/**
Send a one second break signal.
*/
public void sendBreak() {
sPort.sendBreak(1000);
}
/**
Reports the open status of the port.
#return true if port is open, false if port is closed.
*/
public boolean isOpen() {
return open;
}
/**
Handles SerialPortEvents. The two types of SerialPortEvents that this
program is registered to listen for are DATA_AVAILABLE and BI. During
DATA_AVAILABLE the port buffer is read until it is drained, when no more
data is availble and 30ms has passed the method returns. When a BI
event occurs the words BREAK RECEIVED are written to the messageAreaIn.
*/
public void serialEvent(SerialPortEvent e) {
// Create a StringBuffer and int to receive input data.
StringBuffer inputBuffer = new StringBuffer();
int newData = 0;
// Determine type of event.
switch (e.getEventType()) {
// Read data until -1 is returned. If \r is received substitute
// \n for correct newline handling.
case SerialPortEvent.DATA_AVAILABLE:
while (newData != -1) {
try {
newData = is.read();
if (newData == -1) {
break;
}
if ('\r' == (char)newData) {
inputBuffer.append('\n');
} else {
inputBuffer.append((char)newData);
}
} catch (IOException ex) {
System.err.println(ex);
return;
}
}
// Append received data to messageAreaIn.
receptionString=receptionString+ (new String(inputBuffer));
//System.out.print("<-"+receptionString);
break;
// If break event append BREAK RECEIVED message.
case SerialPortEvent.BI:
receptionString=receptionString+("\n--- BREAK RECEIVED ---\n");
}
}
/**
Handles ownership events. If a PORT_OWNERSHIP_REQUESTED event is
received a dialog box is created asking the user if they are
willing to give up the port. No action is taken on other types
of ownership events.
*/
public void ownershipChange(int type) {
/*
if (type == CommPortOwnershipListener.PORT_OWNERSHIP_REQUESTED) {
PortRequestedDialog prd = new PortRequestedDialog(parent);
}
*/
}
/**
A class to handle <code>KeyEvent</code>s generated by the messageAreaOut.
When a <code>KeyEvent</code> occurs the <code>char</code> that is
generated by the event is read, converted to an <code>int</code> and
writen to the <code>OutputStream</code> for the port.
*/
class KeyHandler extends KeyAdapter {
OutputStream os;
/**
Creates the KeyHandler.
#param os The OutputStream for the port.
*/
public KeyHandler(OutputStream os) {
super();
this.os = os;
}
/**
Handles the KeyEvent.
Gets the <code>char</char> generated by the <code>KeyEvent</code>,
converts it to an <code>int</code>, writes it to the <code>
OutputStream</code> for the port.
*/
public void keyTyped(KeyEvent evt) {
char newCharacter = evt.getKeyChar();
if ((int)newCharacter==10) newCharacter = '\r';
System.out.println ((int)newCharacter);
try {
os.write((int)newCharacter);
} catch (IOException e) {
System.err.println("OutputStream write error: " + e);
}
}
}
public void send(String message) {
byte[] theBytes= (message+"\n").getBytes();
for (int i=0; i<theBytes.length;i++){
char newCharacter = (char)theBytes[i];
if ((int)newCharacter==10) newCharacter = '\r';
try {
os.write((int)newCharacter);
} catch (IOException e) {
System.err.println("OutputStream write error: " + e);
}
}
//System.out.println (">'" +message +"' sent");
}
}
SerialConnection.java
package sms;
public class SerialConnectionException extends Exception {
/**
* Constructs a <code>SerialConnectionException</code>
* with the specified detail message.
*
* #param s the detail message.
*/
public SerialConnectionException(String str) {
super(str);
}
/**
* Constructs a <code>SerialConnectionException</code>
* with no detail message.
*/
public SerialConnectionException() {
super();
}
}
SerialParameters.java
package sms;
import javax.comm.SerialPort;
/**
A class that stores parameters for serial ports.
*/
public class SerialParameters {
private String portName;
private int baudRate;
private int flowControlIn;
private int flowControlOut;
private int databits;
private int stopbits;
private int parity;
/**
Default constructer. Sets parameters to no port, 9600 baud, no flow
control, 8 data bits, 1 stop bit, no parity.
*/
public SerialParameters () {
this("",
9600,
SerialPort.FLOWCONTROL_NONE,
SerialPort.FLOWCONTROL_NONE,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE );
}
/**
Paramaterized constructer.
#param portName The name of the port.
#param baudRate The baud rate.
#param flowControlIn Type of flow control for receiving.
#param flowControlOut Type of flow control for sending.
#param databits The number of data bits.
#param stopbits The number of stop bits.
#param parity The type of parity.
*/
public SerialParameters(String portName,
int baudRate,
int flowControlIn,
int flowControlOut,
int databits,
int stopbits,
int parity) {
this.portName = portName;
this.baudRate = baudRate;
this.flowControlIn = flowControlIn;
this.flowControlOut = flowControlOut;
this.databits = databits;
this.stopbits = stopbits;
this.parity = parity;
}
/**
Sets port name.
#param portName New port name.
*/
public void setPortName(String portName) {
this.portName = portName;
}
/**
Gets port name.
#return Current port name.
*/
public String getPortName() {
return portName;
}
/**
Sets baud rate.
#param baudRate New baud rate.
*/
public void setBaudRate(int baudRate) {
this.baudRate = baudRate;
}
/**
Sets baud rate.
#param baudRate New baud rate.
*/
public void setBaudRate(String baudRate) {
this.baudRate = Integer.parseInt(baudRate);
}
/**
Gets baud rate as an <code>int</code>.
#return Current baud rate.
*/
public int getBaudRate() {
return baudRate;
}
/**
Gets baud rate as a <code>String</code>.
#return Current baud rate.
*/
public String getBaudRateString() {
return Integer.toString(baudRate);
}
/**
Sets flow control for reading.
#param flowControlIn New flow control for reading type.
*/
public void setFlowControlIn(int flowControlIn) {
this.flowControlIn = flowControlIn;
}
/**
Sets flow control for reading.
#param flowControlIn New flow control for reading type.
*/
public void setFlowControlIn(String flowControlIn) {
this.flowControlIn = stringToFlow(flowControlIn);
}
/**
Gets flow control for reading as an <code>int</code>.
#return Current flow control type.
*/
public int getFlowControlIn() {
return flowControlIn;
}
/**
Gets flow control for reading as a <code>String</code>.
#return Current flow control type.
*/
public String getFlowControlInString() {
return flowToString(flowControlIn);
}
/**
Sets flow control for writing.
#param flowControlIn New flow control for writing type.
*/
public void setFlowControlOut(int flowControlOut) {
this.flowControlOut = flowControlOut;
}
/**
Sets flow control for writing.
#param flowControlIn New flow control for writing type.
*/
public void setFlowControlOut(String flowControlOut) {
this.flowControlOut = stringToFlow(flowControlOut);
}
/**
Gets flow control for writing as an <code>int</code>.
#return Current flow control type.
*/
public int getFlowControlOut() {
return flowControlOut;
}
/**
Gets flow control for writing as a <code>String</code>.
#return Current flow control type.
*/
public String getFlowControlOutString() {
return flowToString(flowControlOut);
}
/**
Sets data bits.
#param databits New data bits setting.
*/
public void setDatabits(int databits) {
this.databits = databits;
}
/**
Sets data bits.
#param databits New data bits setting.
*/
public void setDatabits(String databits) {
if (databits.equals("5")) {
this.databits = SerialPort.DATABITS_5;
}
if (databits.equals("6")) {
this.databits = SerialPort.DATABITS_6;
}
if (databits.equals("7")) {
this.databits = SerialPort.DATABITS_7;
}
if (databits.equals("8")) {
this.databits = SerialPort.DATABITS_8;
}
}
/**
Gets data bits as an <code>int</code>.
#return Current data bits setting.
*/
public int getDatabits() {
return databits;
}
/**
Gets data bits as a <code>String</code>.
#return Current data bits setting.
*/
public String getDatabitsString() {
switch(databits) {
case SerialPort.DATABITS_5:
return "5";
case SerialPort.DATABITS_6:
return "6";
case SerialPort.DATABITS_7:
return "7";
case SerialPort.DATABITS_8:
return "8";
default:
return "8";
}
}
/**
Sets stop bits.
#param stopbits New stop bits setting.
*/
public void setStopbits(int stopbits) {
this.stopbits = stopbits;
}
/**
Sets stop bits.
#param stopbits New stop bits setting.
*/
public void setStopbits(String stopbits) {
if (stopbits.equals("1")) {
this.stopbits = SerialPort.STOPBITS_1;
}
if (stopbits.equals("1.5")) {
this.stopbits = SerialPort.STOPBITS_1_5;
}
if (stopbits.equals("2")) {
this.stopbits = SerialPort.STOPBITS_2;
}
}
/**
Gets stop bits setting as an <code>int</code>.
#return Current stop bits setting.
*/
public int getStopbits() {
return stopbits;
}
/**
Gets stop bits setting as a <code>String</code>.
#return Current stop bits setting.
*/
public String getStopbitsString() {
switch(stopbits) {
case SerialPort.STOPBITS_1:
return "1";
case SerialPort.STOPBITS_1_5:
return "1.5";
case SerialPort.STOPBITS_2:
return "2";
default:
return "1";
}
}
/**
Sets parity setting.
#param parity New parity setting.
*/
public void setParity(int parity) {
this.parity = parity;
}
/**
Sets parity setting.
#param parity New parity setting.
*/
public void setParity(String parity) {
if (parity.equals("None")) {
this.parity = SerialPort.PARITY_NONE;
}
if (parity.equals("Even")) {
this.parity = SerialPort.PARITY_EVEN;
}
if (parity.equals("Odd")) {
this.parity = SerialPort.PARITY_ODD;
}
}
/**
Gets parity setting as an <code>int</code>.
#return Current parity setting.
*/
public int getParity() {
return parity;
}
/**
Gets parity setting as a <code>String</code>.
#return Current parity setting.
*/
public String getParityString() {
switch(parity) {
case SerialPort.PARITY_NONE:
return "None";
case SerialPort.PARITY_EVEN:
return "Even";
case SerialPort.PARITY_ODD:
return "Odd";
default:
return "None";
}
}
/**
Converts a <code>String</code> describing a flow control type to an
<code>int</code> type defined in <code>SerialPort</code>.
#param flowControl A <code>string</code> describing a flow control type.
#return An <code>int</code> describing a flow control type.
*/
private int stringToFlow(String flowControl) {
if (flowControl.equals("None")) {
return SerialPort.FLOWCONTROL_NONE;
}
if (flowControl.equals("Xon/Xoff Out")) {
return SerialPort.FLOWCONTROL_XONXOFF_OUT;
}
if (flowControl.equals("Xon/Xoff In")) {
return SerialPort.FLOWCONTROL_XONXOFF_IN;
}
if (flowControl.equals("RTS/CTS In")) {
return SerialPort.FLOWCONTROL_RTSCTS_IN;
}
if (flowControl.equals("RTS/CTS Out")) {
return SerialPort.FLOWCONTROL_RTSCTS_OUT;
}
return SerialPort.FLOWCONTROL_NONE;
}
/**
Converts an <code>int</code> describing a flow control type to a
<code>String</code> describing a flow control type.
#param flowControl An <code>int</code> describing a flow control type.
#return A <code>String</code> describing a flow control type.
*/
String flowToString(int flowControl) {
switch(flowControl) {
case SerialPort.FLOWCONTROL_NONE:
return "None";
case SerialPort.FLOWCONTROL_XONXOFF_OUT:
return "Xon/Xoff Out";
case SerialPort.FLOWCONTROL_XONXOFF_IN:
return "Xon/Xoff In";
case SerialPort.FLOWCONTROL_RTSCTS_IN:
return "RTS/CTS In";
case SerialPort.FLOWCONTROL_RTSCTS_OUT:
return "RTS/CTS Out";
default:
return "None";
}
}
}
But when i am trying to run the code, i am getting following error:-
Error loading SolarisSerial: java.lang.UnsatisfiedLinkError: no SolarisSerialParallel in java.library.path
Caught java.lang.UnsatisfiedLinkError: com.sun.comm.SolarisDriver.readRegistrySerial(Ljava/util/Vector;Ljava/lang/String;)I while loading driver com.sun.comm.SolarisDriver
is this code that i have taken OS specific. Or there are any other way to send sms(txt) from pc to mobile.
Please help me.
I think this is a very complicated approach.
If you are developing a commercial application, there are many companies which provide web services that you could use. You just send the sms text to the webservice, and they will send the sms for you, no need to reinvent the wheel.
Unless you are developing a webservice like this yourself!
Your code relies on a JNI driver class "com.sun.comm.SolarisDriver". Your program can't locate the dinamic library SolarisSerialParallel.
The Java virtual machine needs to be able to find the native library. To do this, set the library path adding the path to the library as follows:
Unix or Linux based systems:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH;'/opt/whatever/SolarisSerialParallel.so'
export LD_LIBRARY_PATH
Windows (I guess that in this case, you'll need to search the appropiate DLL, as the one required at your question seems to be exclusive for Solaris environments):
set PATH=%path%;C:\whatever\SolarisSerialParallel.dll
Note that you can point it to the containing directory, if more libraries ar needed.
Reference: Java Native Interface Specification