I'm building a project through GWT and Eclipse for the realization of a site similar to Yahoo Answer, until a few days ago it was working perfectly but since yesterday I noticed a bug that I didn't see before and it's very strange because I would have noticed. Basically on the console of Google Chrome I receive an Uncaught error when I try to visualize the answers related to a question, it seems as if the database (mapdb 1.0.9) does not return anything
For compatibility problems i'm using Eclipse Mars for Java 7 (1.7) and GWT 2.8.0
I will post the part of the code that is not reproduced by clicking on the question
public class MostraRisposte {
private VerticalPanel verticalPanel = null;
public MostraRisposte(VerticalPanel verticalPanel) {
this.verticalPanel = verticalPanel;
}
public void onModuleLoad(Domanda currentSelection) {
this.verticalPanel.add(new HTML("<br>"));
this.verticalPanel.add(new HTML("<br>"));
final Grid answerGridPanel = new Grid(8, 2);
answerGridPanel.setWidget(0, 0, new Label("Utente: "));
answerGridPanel.setWidget(0, 1, new Label(currentSelection.getUserName()));
answerGridPanel.setWidget(1, 0, new Label("Testo: "));
answerGridPanel.setWidget(1, 1, new Label(currentSelection.getText()));
answerGridPanel.setWidget(2, 0, new Label("Data: "));
answerGridPanel.setWidget(2, 1, new Label(currentSelection.getDay()));
answerGridPanel.setWidget(4, 0, new Label("Link1: "));
answerGridPanel.setWidget(4, 1, new Label(currentSelection.getLinkList().get(0)));
answerGridPanel.setWidget(5, 0, new Label("Link2: "));
answerGridPanel.setWidget(5, 1, new Label(currentSelection.getLinkList().get(1)));
answerGridPanel.setWidget(6, 0, new Label("Link3: "));
answerGridPanel.setWidget(6, 1, new Label(currentSelection.getLinkList().get(2)));
answerGridPanel.setWidget(7, 0, new Label("Link4: "));
answerGridPanel.setWidget(7, 1, new Label(currentSelection.getLinkList().get(3)));
this.verticalPanel.add(answerGridPanel);
final GwaServiceAsync gwanswer = GWT.create(GwaService.class);
final int id = currentSelection.getIdQuestion();
gwanswer.ordinaRisposte(id, new AsyncCallback<List<Risposta>>() {
#Override
public void onFailure(Throwable caught) {
PopupPanel popup = new PopupPanel(true);
popup.setWidget(new HTML("<font color='red'>Errore</font>"));
popup.center();
}
#Override
public void onSuccess(List<Risposta> response) {
final CellTable<Risposta> questionsTable = new CellTable<>(20);
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getText();
}
}, "Risposta");
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta answer) {
return answer.getUserName();
}
}, "Utente");
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getDay();
}
}, "Giorno");
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getTime();
}
}, "Ora");
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getJudgeEmail();
}
}, "Giudice");
final TextColumn<Risposta> ratingTextColumn = new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getRating();
}
};
questionsTable.addColumn(ratingTextColumn, "Voto");
ratingTextColumn.setSortable(true);
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getLinkList().get(0);
}
}, "Link");
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getLinkList().get(1);
}
}, "Link");
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getLinkList().get(2);
}
}, "Link");
questionsTable.addColumn(new TextColumn<Risposta>() {
#Override
public String getValue(Risposta risposta) {
return risposta.getLinkList().get(3);
}
}, "Link");
final ListDataProvider<Risposta> dataProvider = new ListDataProvider<>();
dataProvider.addDataDisplay(questionsTable);
final List<Risposta> list = dataProvider.getList();
for (Iterator<Risposta> iterator = response.iterator(); iterator.hasNext();) {
final Risposta risposta = iterator.next();
list.add(risposta);
}
final ListHandler<Risposta> columnSortHandler = new ListHandler<>(list);
columnSortHandler.setComparator(ratingTextColumn, new Comparator<Risposta>() {
#Override
public int compare(Risposta option1, Risposta option2) {
if (option1.getRating().equals(option2.getRating())) {
if (!option1.getDate().after(option2.getDate())) {
return -1;
} else {
return 1;
}
} else {
return (option2 != null && option1 != null) ? option1.getRating().compareTo(option2.getRating())
: 1;
}
}
});
questionsTable.addColumnSortHandler(columnSortHandler);
questionsTable.getColumnSortList().push(ratingTextColumn);
questionsTable.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
final SingleSelectionModel<Risposta> selectionModel = new SingleSelectionModel<>();
questionsTable.setSelectionModel(selectionModel);
selectionModel.addSelectionChangeHandler(new Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
if (UtenteAttuale.accountType == 1) {
final Risposta currentSelection1 = selectionModel.getSelectedObject();
if (currentSelection1 != null) {
final AggiungiVoto iv = new AggiungiVoto(MostraRisposte.this.verticalPanel);
iv.onModuleLoad(currentSelection1);
}
}
}
});
questionsTable.setRowCount(response.size(), true);
questionsTable.setRowData(0, response);
MostraRisposte.this.verticalPanel.add(questionsTable);
}
});
}
}
I expect to display a grid (Grid) with the information of who made the question I selected (CurrentSelection) and immediately below the table containing the answers, I checked and the questions and answers are correctly entered in the database but unfortunately only the answers do not appear.
The error on Chrome console:
Try to catch all uncaught exceptions, and unwrap the umbrella.
Somewhere in the beginnen of your onModuleLoad method
GWT.setUncaughtExceptionHandler(e -> showError(e));
And in showError do something like
Throwable unwrapped = unwrap(e);
GWT.log("Uncaught exception catched", unwrapped);
/**
* Unwrap the given exception.
* #param e The exception.
* #return Unwrapped version of the exception
*/
private static Throwable unwrap(Throwable e)
{
if (e instanceof UmbrellaException)
{
UmbrellaException ue = (UmbrellaException) e;
if (ue.getCauses().size() == 1)
{
return unwrap(ue.getCauses().iterator().next());
}
}
return e;
}
This way you have a much cleaner stacktrace to see what has happened.
Related
I have successfully implemented this github library for SSE Handling in Android.
The problem
Each time i'm sending data to the stream , the onMessage function is triggered successfully. Although the provided data field of MessageEvent is empty.
My Implementation
Main.java
private SSEHandler sseHandler = new SSEHandler();
private EventSource eventSource;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startEventSource();
}
private void startEventSource() {
eventSource = new EventSource.Builder(".../ambulance/assign/receive")
.eventHandler(sseHandler)
// .headers()
.build();
eventSource.connect();
}
private void stopEventSource() {
if (eventSource != null)
eventSource.close();
sseHandler = null;
}
SSEHandler.java
public class SSEHandler implements EventSourceHandler {
public SSEHandler() {}
#Override
public void onConnect() {
Log.e("SSE Connected", "True");
}
#Override
public void onMessage(String event, MessageEvent message) {
Log.e("SSE Message", event);
Log.e("SSE Message: ", String.valueOf(message));
}
#Override
public void onComment(String comment) {
//comments only received if exposeComments turned on
Log.e("SSE Comment", comment);
}
#Override
public void onError(Throwable t) {
//ignore ssl NPE on eventSource.close()
Log.e("SSE Error", "Error");
}
#Override
public void onClosed(boolean willReconnect) {
Log.e("SSE Closed", "reconnect? " + willReconnect);
}
}
Server Side Endpoint
#RequestMapping(method = RequestMethod.GET, value = "/ambulance/assign/receive")
public Flux < MessageEvent > addReport() {
return Flux.create(sink -> {
assignProcessor.register(sink::next);
});
}
No matter what is the return type of Flux <Object> the data field
is always empty on android
POST payload & MessageEvent Object
Payload
{
"data": "test",
"lastEventId": "tester",
"origin": "my origin"
}
MessageEvent.java
public class MessageEvent {
public String data;
public String lastEventId;
public String origin;
public MessageEvent(String data, String lastEventId, String origin) {
this.data = data;
this.lastEventId = lastEventId;
this.origin = origin;
}
public MessageEvent(String data) {
this(data, null, null);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MessageEvent that = (MessageEvent) o;
if (data != null ? !data.equals(that.data) : that.data != null) return false;
if (lastEventId != null ? !lastEventId.equals(that.lastEventId) : that.lastEventId != null) return false;
if (origin != null ? !origin.equals(that.origin) : that.origin != null) return false;
return true;
}
#Override
public int hashCode() {
int result = data != null ? data.hashCode() : 0;
result = 31 * result + (lastEventId != null ? lastEventId.hashCode() : 0);
result = 31 * result + (origin != null ? origin.hashCode() : 0);
return result;
}
#Override
public String toString() {
return "MessageEvent{" +
"data='" + data + '\'' +
", lastEventId='" + lastEventId + '\'' +
", origin='" + origin + '\'' +
'}';
}
}
Already tried with : Flux <String> data is still empty.
Based on this EventStreamParser I assume that it should parse as data every Object in JSON format because of this function.
private void processField(String field, String value)
I even tried plain text, but didn't seem to work either...
I managed to read the Object using another java library
This one:
Maven
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.7.2</version>
</dependency>
Gradle
// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.7.2'
Buildr
# https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
'com.squareup.okhttp3:okhttp:jar:4.7.2'
Implemented EventSource as before
public class SimpleEventHandler implements EventHandler {
#Override
public void onOpen() throws Exception {
System.out.println("onOpen");
}
#Override
public void onClosed() throws Exception {
System.out.println("onClosed");
}
#Override
public void onMessage(String event, MessageEvent messageEvent) throws Exception {
System.out.println(messageEvent.getData());
}
#Override
public void onComment(String comment) throws Exception {
System.out.println("onComment");
}
#Override
public void onError(Throwable t) {
System.out.println("onError: " + t);
}
}
Main method
public static void main(String[] args) throws InterruptedException, ExecutionException, UnknownHostException, IOException {
EventHandler eventHandler = new SimpleEventHandler();
String url = String.format("https://aedproject.herokuapp.com/api/ambulance/assign/receive");
EventSource.Builder builder = new EventSource.Builder(eventHandler, URI.create(url))
.reconnectTime(Duration.ofMillis(3000));
try (EventSource eventSource = builder.build()) {
eventSource.start();
TimeUnit.MINUTES.sleep(10);
} catch (Exception e) {
}
This time, the data filed of MessageEvent contains my whole Object!
I'm implementing PositionalDataSource from Paging Library in Java and getting an issue that constructor of PositionalDataSource's child class is getting called but after that loadInitial method is not getting called.
public HistoryPositionalDataSource(List<CallTable> callLogs)
{
this.callLogs = callLogs;
Log.d("PaginationDataSource", "Constructor");
}
#Override
public void loadInitial(#NonNull LoadInitialParams params, #NonNull LoadInitialCallback callback) {
Log.d("PaginationDataSource", "loadInitial");
if (callLogs!=null && !callLogs.isEmpty())
{
int totalCount = computeCount();
int position = computeInitialLoadPosition(params, totalCount);
int loadSize = computeInitialLoadSize(params, position, totalCount);
callback.onResult(loadRangeInternal(position, loadSize), position, totalCount);
}
}
#Override
public void loadRange(#NonNull LoadRangeParams params, #NonNull LoadRangeCallback callback) {
callback.onResult(loadRangeInternal(params.startPosition, params.loadSize));
}
Here's my PageListConfig
private void init() {
pagedListConfig = (new PagedList.Config.Builder()).setEnablePlaceholders(true)
.setInitialLoadSizeHint(Integer.MAX_VALUE).setPageSize(Integer.MAX_VALUE).build();
Executor executor = Executors.newFixedThreadPool(3);
List<CallTable> listLogs = getCallLogs(context);
historyDataSourceFactory = new HistoryDataSourceFactory(listLogs);
LivePagedListBuilder livePagedListBuilder = new LivePagedListBuilder(historyDataSourceFactory, pagedListConfig);
pagedCallLogs = livePagedListBuilder
.setFetchExecutor(executor)
.build();
}
Factory class:
public class HistoryDataSourceFactory extends DataSource.Factory {
private static final String TAG = HistoryDataSourceFactory.class.getSimpleName();
private HistoryPositionalDataSource historyPositionalDataSource;
public HistoryDataSourceFactory(List<CallTable> callLogs)
{
if (callLogs!=null && !callLogs.isEmpty())
{
Log.d("PaginationFactory", "NotNullLogs");
historyPositionalDataSource = new HistoryPositionalDataSource(callLogs);
}
}
#Override
public DataSource create() {
return historyPositionalDataSource;
}
}
My getPagedCallLogs method:
public synchronized LiveData<PagedList<CallTable>> getPagedCallLogs() {
if (pagedCallLogs!=null && pagedCallLogs.getValue()!=null)
{
Log.d("PagingGetData", "Done");
return pagedCallLogs;
}
else
{
Log.d("PagingGetData", "Null");
return null;
}
}
Logs image is given below.
Load size and offset is set
via PagedList.Config so you don't need to calculate load range yourself.
Change your loadInitial function
#Override
public void loadInitial(#NonNull LoadInitialParams params, #NonNull LoadInitialCallback callback) {
Log.d("PaginationDataSource", "loadInitial");
if (callLogs!=null && !callLogs.isEmpty())
{
callback.onResult(loadRangeInternal(0, params.requestedLoadSize), 0);
}
}
Edit:
Try this config aswell
PagedList.Config config =
new PagedList.Config.Builder()
.setPageSize(50)
.setEnablePlaceholders(false)
.setPrefetchDistance(25)
.build();
Edit2:
Try changing extention from DataSource.Factory to DataSource.Factory<Integer, ModelClass> and PositionalDataSource to PositionalDataSource<ModelClass>
After too many struggle, I become able to resolve my issue. The issue was with my getPagedCallLog method.
I wrote:
public synchronized LiveData<PagedList<CallTable>> getPagedCallLogs() {
if (pagedCallLogs!=null && pagedCallLogs.getValue()!=null)
{
Log.d("PagingGetData", "Done");
return pagedCallLogs;
}
else
{
Log.d("PagingGetData", "Null");
return null;
}
}
I was taking Google I/O '18, in which he said that loadInitial is called by the pageList, then I realise that it wasn't getting called in my case. And it is working fine after removing pagedCallLogs.getValue()!=null which was my stupid mistake.
Now it looks like this:
public synchronized LiveData<PagedList<CallTable>> getPagedCallLogs() {
if (pagedCallLogs!=null)
{
Log.d("PagingGetData", "Done");
return pagedCallLogs;
}
else
{
Log.d("PagingGetData", "Null");
return null;
}
}
The problem here is I have filter menu and I have to select one label with a checkbox when I run the test in UI it shows the checkbox is checking but it's failing at checkbox verification and throwing waiter exception. "Wait.until(isChecked());" at this point.
/* My Test Case*/
public void testCustomFieldBooleanVerification() {
NamedAccountsSection tab = NamedAccountSection;
tab.filterToggle.toggleOn();
tab.openFilterMenu().openAddFilterMenu().addFilter("ABM CUST BOOL3");
tab.openFilterMenu().closeAddFilterMenu();
tab.openFilterMenu().apply();
/* addFilter */
public AddFilterMenu addFilter(String filter) {
logger.debug("Adding filter:" + filter);
MktCheckBox checkbox = new MktCheckBox(new MktLabel(filter, locator).getLabeledInputLocator());
if (Check.that(checkbox.isCheckable())) {
checkbox.check();
}
return this;
}
/* CheckBox*/
public MktCheckBox(By locator, String description) {
super(locator, description);
}
/* check box condition*/
public MktCheckBox check() throws TimeoutException {
if (!Check.that(isUnchecked()) || !Check.that(isEnabled())) {
logger.warn(String.format("%s is already checked", description));
} else {
Wait.until(isCheckable());
logger.debug(String.format("Clicking on %s", description));
click();
Wait.until(isChecked());
}
return this;
}
public Waiter<Boolean> isChecked() {
return new Waiter<>(Connection.getWebDriver(), (ExpectedCondition<Boolean>) webDriver -> GuiObjectControl.isSelected(webElement));
}
/* Label Locator*/
public class MktLabel extends MktText {
static final String LABELED_IDENTIFIER = "//*[#id=(//label[text()='%s']/#for)]";
static final String LABEL_IDENTIFIER = "//label[text()='%s']";
protected String label;
public By getLabeledInputLocator() {
if(label == null) {
label = this.getText();
}
return By.xpath(String.format(LABELED_IDENTIFIER, label));
}
I have problem of playing back the recorded media file from red5 published stream, following is my code. I could see a file called out.flv is created, but this out.flv can not be played back.
public class Red5ClientTest {
private static Timer timer;
private static RTMPClient client;
private static String sourceStreamName;
private static int videoTs;
private static int audioTs;
private static FLVWriter writer;
private static int bytesRead =0;
public static void main(String[] args) throws IOException {
String sourceHost = "localhost";
int sourcePort = 1935;
String sourceApp = "oflaDemo";
sourceStreamName = "myStream";
timer = new Timer();
client = new RTMPClient();
String path = "c:\\temp\\out.flv";
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
writer = new FLVWriter(file,true);
client.setStreamEventDispatcher(new StreamEventDispatcher());
client.setStreamEventHandler(new INetStreamEventHandler() {
public void onStreamEvent(Notify notify) {
System.out.printf("onStreamEvent: %s\n", notify);
ObjectMap<?, ?> map = (ObjectMap<?, ?>) notify.getCall().getArguments()[0];
String code = (String) map.get("code");
System.out.printf("<:%s\n", code);
if (StatusCodes.NS_PLAY_STREAMNOTFOUND.equals(code)) {
System.out.println("Requested stream was not found");
client.disconnect();
}
else if (StatusCodes.NS_PLAY_UNPUBLISHNOTIFY.equals(code)
|| StatusCodes.NS_PLAY_COMPLETE.equals(code)) {
System.out.println("Source has stopped publishing or play is complete");
client.disconnect();
}
}
});
client.setConnectionClosedHandler(new Runnable() {
public void run() {
if (writer != null) {
writer.close();
}
System.out.println("Source connection has been closed, proxy will be stopped");
System.exit(0);
}
});
client.setExceptionHandler(new ClientExceptionHandler() {
#Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
System.exit(1);
}
});
// connect the consumer
Map<String, Object> defParams = client.makeDefaultConnectionParams(sourceHost, sourcePort,
sourceApp);
// add pageurl and swfurl
defParams.put("pageUrl", "");
defParams.put("swfUrl", "app:/Red5-StreamRelay.swf");
// indicate for the handshake to generate swf verification data
client.setSwfVerification(true);
// connect the client
client.connect(sourceHost, sourcePort, defParams, new IPendingServiceCallback() {
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
ObjectMap<?, ?> map = (ObjectMap<?, ?>) call.getResult();
String code = (String) map.get("code");
if ("NetConnection.Connect.Rejected".equals(code)) {
System.out.printf("Rejected: %s\n", map.get("description"));
client.disconnect();
//proxy.stop();
}
else if ("NetConnection.Connect.Success".equals(code)) {
// 1. Wait for onBWDone
timer.schedule(new BandwidthStatusTask(), 2000L);
Object result = call.getResult();
System.out.println("Red5ClientTest.main()");
}
else {
System.out.printf("Unhandled response code: %s\n", code);
}
}
});
// keep sleeping main thread while the proxy runs
// kill the timer
//timer.cancel();
System.out.println("Stream relay exit");
}
/**
* Handles result from subscribe call.
*/
private static final class SubscribeStreamCallBack implements IPendingServiceCallback {
public void resultReceived(IPendingServiceCall call) {
System.out.println("resultReceived: " + call);
Object result = call.getResult();
System.out.println("results came {}" + result);
}
}
private static final class StreamEventDispatcher implements IEventDispatcher {
public void dispatchEvent(IEvent event) {
System.out.println("ClientStream.dispachEvent()" + event.toString());
try {
//RTMPMessage build = RTMPMessage.build((IRTMPEvent) event);
IRTMPEvent rtmpEvent = (IRTMPEvent) event;
ITag tag = new Tag();
tag.setDataType(rtmpEvent.getDataType());
if (rtmpEvent instanceof VideoData) {
videoTs += rtmpEvent.getTimestamp();
tag.setTimestamp(videoTs);
}
else if (rtmpEvent instanceof AudioData) {
audioTs += rtmpEvent.getTimestamp();
tag.setTimestamp(audioTs);
}
IoBuffer data = ((IStreamData) rtmpEvent).getData().asReadOnlyBuffer();
tag.setBodySize(data.limit());
tag.setBody(data);
try {
writer.writeTag(tag);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("writting....");
}
catch (Exception e) {//IOException
e.printStackTrace();
}
}
}
private static final class BandwidthStatusTask extends TimerTask {
#Override
public void run() {
// check for onBWDone
System.out.println("Bandwidth check done: " + client.isBandwidthCheckDone());
// cancel this task
this.cancel();
// create a task to wait for subscribed
timer.schedule(new PlayStatusTask(), 1000L);
// 2. send FCSubscribe
client.subscribe(new SubscribeStreamCallBack(), new Object[] { sourceStreamName });
}
}
private static final class PlayStatusTask extends TimerTask {
#Override
public void run() {
// checking subscribed
System.out.println("Subscribed: " + client.isSubscribed());
// cancel this task
this.cancel();
// 3. create stream
client.createStream(new CreateStreamCallback());
}
}
/**
* Creates a "stream" via playback, this is the source stream.
*/
private static final class CreateStreamCallback implements IPendingServiceCallback {
public void resultReceived(IPendingServiceCall call) {
System.out.println("resultReceived: " + call);
int streamId = ((Number) call.getResult()).intValue();
System.out.println("stream id: " + streamId);
// send our buffer size request
if (sourceStreamName.endsWith(".flv") || sourceStreamName.endsWith(".f4v")
|| sourceStreamName.endsWith(".mp4")) {
client.play(streamId, sourceStreamName, 0, -1);
}
else {
client.play(streamId, sourceStreamName, -1, 0);
}
}
}
}
what could I be doing possibly wrong here?
Finally got it
public class TeqniRTMPClient {
private static final Logger logger = LoggerFactory.getLogger(MyRtmpClient.class);
public static void main(String args[]) throws IOException {
TeqniRTMPClient client = new TeqniRTMPClient("localhost", 1935, "oflaDemo", "myStream");
client.recordStream();
}
private RTMPClient client;
private ITagWriter writer;
private String sourceHost;
private int sourcePort;
private String sourceApp;
private String sourceStreamName;
private int lastTimestamp;
private int startTimestamp = -1;
public TeqniRTMPClient(String sourceHost, int sourcePort, String sourceApp,
String sourceStreamName) {
super();
this.sourceHost = sourceHost;
this.sourcePort = sourcePort;
this.sourceApp = sourceApp;
this.sourceStreamName = sourceStreamName;
}
public void recordStream() throws IOException {
client = new RTMPClient();
String path = "c:\\temp\\out.flv";
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
FLVService flvService = new FLVService();
flvService.setGenerateMetadata(true);
try {
IStreamableFile flv = flvService.getStreamableFile(file);
writer = flv.getWriter();
}
catch (Exception e) {
throw new RuntimeException(e);
}
client.setStreamEventDispatcher(new StreamEventDispatcher());
client.setStreamEventHandler(new INetStreamEventHandler() {
public void onStreamEvent(Notify notify) {
System.out.printf("onStreamEvent: %s\n", notify);
ObjectMap<?, ?> map = (ObjectMap<?, ?>) notify.getCall().getArguments()[0];
String code = (String) map.get("code");
System.out.printf("<:%s\n", code);
if (StatusCodes.NS_PLAY_STREAMNOTFOUND.equals(code)) {
System.out.println("Requested stream was not found");
client.disconnect();
}
else if (StatusCodes.NS_PLAY_UNPUBLISHNOTIFY.equals(code)
|| StatusCodes.NS_PLAY_COMPLETE.equals(code)) {
System.out.println("Source has stopped publishing or play is complete");
client.disconnect();
}
}
});
client.setExceptionHandler(new ClientExceptionHandler() {
#Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
System.exit(1);
}
});
client.setConnectionClosedHandler(new Runnable() {
public void run() {
if (writer != null) {
writer.close();
}
System.out.println("Source connection has been closed, proxy will be stopped");
System.exit(0);
}
});
// connect the consumer
Map<String, Object> defParams = client.makeDefaultConnectionParams(sourceHost, sourcePort,
sourceApp);
// add pageurl and swfurl
defParams.put("pageUrl", "");
defParams.put("swfUrl", "app:/Red5-StreamRelay.swf");
// indicate for the handshake to generate swf verification data
client.setSwfVerification(true);
// connect the client
client.connect(sourceHost, sourcePort, defParams, new IPendingServiceCallback() {
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
ObjectMap<?, ?> map = (ObjectMap<?, ?>) call.getResult();
String code = (String) map.get("code");
if ("NetConnection.Connect.Rejected".equals(code)) {
System.out.printf("Rejected: %s\n", map.get("description"));
client.disconnect();
}
else if ("NetConnection.Connect.Success".equals(code)) {
// 1. Wait for onBWDone
client.createStream(new CreateStreamCallback());
Object result = call.getResult();
System.out.println("Red5ClientTest.main()");
}
else {
System.out.printf("Unhandled response code: %s\n", code);
}
}
});
}
class CreateStreamCallback implements IPendingServiceCallback {
public void resultReceived(IPendingServiceCall call) {
System.out.println("resultReceived: " + call);
int streamId = ((Number) call.getResult()).intValue();
System.out.println("stream id: " + streamId);
// send our buffer size request
if (sourceStreamName.endsWith(".flv") || sourceStreamName.endsWith(".f4v")
|| sourceStreamName.endsWith(".mp4")) {
client.play(streamId, sourceStreamName, 0, -1);
}
else {
client.play(streamId, sourceStreamName, -1, 0);
}
}
}
class StreamEventDispatcher implements IEventDispatcher {
private int videoTs;
private int audioTs;
public void dispatchEvent(IEvent event) {
System.out.println("ClientStream.dispachEvent()" + event.toString());
try {
IRTMPEvent rtmpEvent = (IRTMPEvent) event;
logger.debug("rtmp event: " + rtmpEvent.getHeader() + ", "
+ rtmpEvent.getClass().getSimpleName());
if (!(rtmpEvent instanceof IStreamData)) {
logger.debug("skipping non stream data");
return;
}
if (rtmpEvent.getHeader().getSize() == 0) {
logger.debug("skipping event where size == 0");
return;
}
byte dataType = rtmpEvent.getDataType();
ITag tag = new Tag();
tag.setDataType(dataType);
if (rtmpEvent instanceof VideoData) {
VideoData video = (VideoData) rtmpEvent;
FrameType frameType = video.getFrameType();
videoTs += rtmpEvent.getTimestamp();
tag.setTimestamp(videoTs);
}
else if (rtmpEvent instanceof AudioData) {
audioTs += rtmpEvent.getTimestamp();
tag.setTimestamp(audioTs);
}
IoBuffer data = ((IStreamData) rtmpEvent).getData().asReadOnlyBuffer();
tag.setBodySize(data.limit());
tag.setBody(data);
try {
writer.writeTag(tag);
}
catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("writting....");
}
catch (Exception e) {//IOException
e.printStackTrace();
}
}
}
}
I have some old playframework 2.2 java webservice that interacts with akka, and now I should port them to playframework 2.3.
However, async has been deprecated and even after reading the doc about the async porting (http://www.playframework.com/documentation/2.3.x/JavaAsync) I wasn't able to understand how to apply it to my case (code below):
I must make the await for a timeout/akka server reply before starting the construction of my reply (ok()), otherwise I will block the thread.
I should make the actorselection async too.
I should make the akka server reply parsing/reply construction async too
I looked around and I wasn't able to find an example of such interactions, even in typesafe templates.
How could I do that?
/* playframework 2.2 code */
public class Resolve extends Controller {
private final static String RESOLVER_ACTOR = play.Play.application().configuration().getString("actor.resolve");
#CorsRest
#VerboseRest
#RequireAuthentication
#BodyParser.Of(BodyParser.Json.class)
public static Result getJsonTree() {
JsonNode json = request().body().asJson();
ProtoBufMessages.ResolveRequest msg;
ResolveRequestInput input;
try {
input = new ResolveRequestInput(json);
} catch (rest.exceptions.MalformedInputException mie) {
return badRequest(mie.getMessage());
}
msg = ((ProtoBufMessages.ResolveRequest)input.getMessage());
ActorSelection resolver = Akka.system().actorSelection(RESOLVER_ACTOR);
Timeout tim = new Timeout(Duration.create(4, "seconds"));
Future<Object> fut = Patterns.ask(resolver, input.getMessage(), tim);
return async (
F.Promise.wrap(fut).map(
new F.Function<Object, Result>() {
public Result apply(Object response) {
ProtoBufMessages.ResolveReply rsp = ((ProtoBufMessages.ResolveReply)response);
ResolveOutput output = new ResolveOutput(rsp);
return ok(output.getJsonReply());
}
}
)
);
}
}
I came out with the code below
public class Resolve extends Controller {
private final static String RESOLVER_ACTOR = play.Play.application().configuration().getString("actor.resolve");
private final static BrainProtoMessages.ResolveReply request_error = BrainProtoMessages.ResolveReply.newBuilder()
.setReturnCode(BResults.REQUEST_FAILED)
.build();
#CorsRest
#VerboseRest
#RequireAuthentication
#BodyParser.Of(BodyParser.Json.class)
public static Result resolve_map() {
final ResolveRequestInput input;
final F.Promise<ActorSelection> selected_target;
final F.Promise<Future<Object>> backend_request;
final F.Promise<BrainProtoMessages.ResolveReply> backend_reply;
final F.Promise<ObjectNode> decode_json;
final F.Promise<Result> ok_result;
final JsonNode json = request().body().asJson();
try {
input = new ResolveRequestInput(json);
} catch (rest.exceptions.MalformedInputException mie) {
return badRequest(mie.getMessage());
}
selected_target = F.Promise.promise(
new F.Function0<ActorSelection>() {
#Override
public ActorSelection apply() throws Throwable {
return Akka.system().actorSelection(RESOLVER_ACTOR);
}
}
);
backend_request =
selected_target.map(
new F.Function<ActorSelection, Future<Object>>() {
#Override
public Future<Object> apply(ActorSelection actorSelection) throws Throwable {
return Patterns.ask(actorSelection, input.getMessage(),new Timeout(Duration.create(4, "seconds")));
}
}
);
backend_reply = backend_request.map(
new F.Function<Future<Object>, BrainProtoMessages.ResolveReply>() {
#Override
public BrainProtoMessages.ResolveReply apply(Future<Object> akka_reply) throws Throwable {
try {
return (BrainProtoMessages.ResolveReply) Await.result(akka_reply, Duration.create(4, "seconds"));
}catch(Exception error)
{
return request_error;
}
}
}
);
decode_json = backend_reply.map(
new F.Function<BrainProtoMessages.ResolveReply, ObjectNode>() {
#Override
public ObjectNode apply(BrainProtoMessages.ResolveReply response) throws Throwable {
return new ResolveOutput(response).getJsonReply();
}
}
);
ok_result = decode_json.map(
new F.Function<ObjectNode, Result>() {
#Override
public Result apply(ObjectNode reply) {
return ok(reply);
}
}
);
try {
return ok_result.get(8000);
}catch(Exception error)
{
return internalServerError();
}
}
}