Revision: 8418
Author: [email protected]
Date: Mon Jul 26 15:35:20 2010
Log: Add basic logging to Scaffold app
Review at http://gwt-code-reviews.appspot.com/651803
Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=8418
Added:
/trunk/user/src/com/google/gwt/requestfactory/client/RequestFactoryLogHandler.java
/trunk/user/src/com/google/gwt/requestfactory/server/Logging.java
/trunk/user/src/com/google/gwt/requestfactory/shared/LoggingRequest.java
Modified:
/trunk/bikeshed/src/com/google/gwt/sample/expenses/gwt/Scaffold.gwt.xml
/trunk/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
/trunk/user/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
/trunk/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java
=======================================
--- /dev/null
+++
/trunk/user/src/com/google/gwt/requestfactory/client/RequestFactoryLogHandler.java
Mon Jul 26 15:35:20 2010
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+
+package com.google.gwt.requestfactory.client;
+
+import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.requestfactory.shared.RequestFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * A Handler that does Remote Logging for applications using Request
Factory
+ */
+public class RequestFactoryLogHandler extends Handler {
+ class LoggingReceiver implements Receiver<Long> {
+ @Override
+ public void onSuccess(Long response) {
+ if (response > 0) {
+ logger.finest("Remote logging successful");
+ } else {
+ logger.finest("Remote logging failed");
+ }
+ }
+ }
+
+ private static Logger logger =
+ Logger.getLogger(RequestFactoryLogHandler.class.getName());
+
+ private boolean closed;
+ private List<LogRecord> records;
+ private RequestFactory requestFactory;
+
+ public RequestFactoryLogHandler(RequestFactory requestFactory) {
+ this(requestFactory, Level.INFO);
+ }
+
+ /**
+ * Since records from this handler go accross the wire, it should only be
+ * used for important messages, and it's Level will often be higher than
the
+ * Level being used app-wide.
+ * Do not set the level of this handler below FINER messages, since it
logs
+ * messages at that level to acknowledge success/failure, and would cause
+ * an infinite loop.
+ */
+ public RequestFactoryLogHandler(RequestFactory requestFactory, Level
level) {
+ this.requestFactory = requestFactory;
+ closed = false;
+ records = new ArrayList<LogRecord>();
+ setLevel(level);
+ }
+
+ @Override
+ public void close() {
+ flush();
+ closed = true;
+ }
+
+ @Override
+ public void flush() {
+ if (!closed) {
+ // We go ahead and just send a request for every message. The request
+ // factory will take care of the batching for us. Once we can send
+ // something more complex than Strings to the logMessage function,
then
+ // we can do batching here.
+ for (LogRecord record : records) {
+ Receiver loggingReciever = new LoggingReceiver();
+ requestFactory.loggingRequest().logMessage(
+ record.getLevel().toString(),
+ record.getLoggerName(),
+ record.getMessage()).to(loggingReciever).fire();
+ }
+ }
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ if (!closed && isLoggable(record)) {
+ records.add(record);
+ // For now, just flush every time since a new request is sent for
every
+ // record anyway.
+ flush();
+ }
+ }
+
+}
=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/requestfactory/server/Logging.java Mon
Jul 26 15:35:20 2010
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+
+package com.google.gwt.requestfactory.server;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Server side object that handles log messages sent by
+ * {...@requestfactoryloghandler}
+ */
+public class Logging {
+ private static Logger logger = Logger.getLogger(Logging.class.getName());
+
+ public static Long logMessage(
+ String levelString, String loggerName, String originalMessage) {
+ Level level = Level.SEVERE;
+ try {
+ level = Level.parse(levelString);
+ } catch (IllegalArgumentException e) {
+ return 0L;
+ }
+ String message = String.format("Client Side Logger: %s Message: %s",
+ loggerName, originalMessage);
+
+ logger.log(level, message);
+ return 1L;
+ }
+
+ private Long id = 0L;
+ private Integer version = 0;
+
+ public Long getId() {
+ return this.id;
+ }
+
+ public Integer getVersion() {
+ return this.version;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+}
+
=======================================
--- /dev/null
+++
/trunk/user/src/com/google/gwt/requestfactory/shared/LoggingRequest.java
Mon Jul 26 15:35:20 2010
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+
+package com.google.gwt.requestfactory.shared;
+
+import com.google.gwt.requestfactory.server.Logging;
+
+/**
+ * "API Generated" request selector interface implemented by objects that
give
+ * client access to the methods of {...@link Logging}.
+ * <p>
+ * IRL this class will be generated by a JPA-savvy tool run before
compilation.
+ */
+...@service(Logging.class)
+public interface LoggingRequest {
+
+ // Should be returning something better than a Long, but that's all that
is
+ // supported for now, so using it as a boolean.
+ // Should also be passing something better than a series of strings, but
+ // that's the only possibility for now.
+ RequestFactory.RequestObject<Long> logMessage(
+ String level, String loggerName, String message);
+
+}
=======================================
--- /trunk/bikeshed/src/com/google/gwt/sample/expenses/gwt/Scaffold.gwt.xml
Fri May 28 08:44:36 2010
+++ /trunk/bikeshed/src/com/google/gwt/sample/expenses/gwt/Scaffold.gwt.xml
Mon Jul 26 15:35:20 2010
@@ -18,7 +18,22 @@
<module rename-to="scaffold">
<inherits name="com.google.gwt.user.User" />
<inherits name="com.google.gwt.user.theme.standard.Standard" />
+ <inherits name="com.google.gwt.logging.Logging"/>
<inherits name="com.google.gwt.sample.expenses.gwt.ExpensesCommon" />
<entry-point class="com.google.gwt.sample.expenses.gwt.client.Scaffold"
/>
+
+ <!-- Logging Configuration -->
+ <!-- Right now, App Engine Dev Mode logging is borken for everything
other
+ than the system handler, so only that one is enabled for now -->
+ <set-property name="gwt.logging.enabled" value="TRUE"/>
+ <set-property name="gwt.logging.logLevel" value="INFO"/>
+ <set-property name="gwt.logging.consoleHandler" value="DISABLED" />
+ <set-property name="gwt.logging.developmentModeHandler" value="DISABLED"
/>
+ <set-property name="gwt.logging.firebugHandler" value="DISABLED" />
+ <set-property name="gwt.logging.hasWidgetsHandler" value="DISABLED" />
+ <set-property name="gwt.logging.popupHandler" value="DISABLED" />
+ <set-property name="gwt.logging.systemHandler" value="ENABLED" />
+ <set-property name="gwt.logging.simpleRemoteHandler" value="DISABLED" />
+
</module>
=======================================
---
/trunk/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
Fri Jul 23 10:49:57 2010
+++
/trunk/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
Mon Jul 26 15:35:20 2010
@@ -22,11 +22,12 @@
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
+import com.google.gwt.requestfactory.client.RequestFactoryLogHandler;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.RequestEvent;
+import com.google.gwt.requestfactory.shared.RequestEvent.State;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.SyncRequest;
-import com.google.gwt.requestfactory.shared.RequestEvent.State;
import com.google.gwt.requestfactory.shared.impl.RequestDataManager;
import com.google.gwt.valuestore.client.DeltaValueStoreJsonImpl;
import com.google.gwt.valuestore.client.ValueStoreJsonImpl;
@@ -35,6 +36,8 @@
import com.google.gwt.valuestore.shared.impl.RecordToTypeMap;
import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* <p>
@@ -46,10 +49,15 @@
*/
public abstract class RequestFactoryJsonImpl implements RequestFactory {
+ private static Logger logger =
+ Logger.getLogger(RequestFactory.class.getName());
+
+ private static String SERVER_ERROR = "Server Error";
+
private HandlerManager handlerManager;
private ValueStoreJsonImpl valueStore;
-
+
public void fire(final RequestObject<?> requestObject) {
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST,
GWT.getHostPageBaseURL() + RequestFactory.URL);
@@ -58,16 +66,16 @@
public void onError(Request request, Throwable exception) {
postRequestEvent(State.RECEIVED, null);
- // shell.error.setInnerText(SERVER_ERROR);
+ logger.log(Level.SEVERE, SERVER_ERROR, exception);
}
public void onResponseReceived(Request request, Response response) {
+ logger.finest("Response received");
if (200 == response.getStatusCode()) {
String text = response.getText();
requestObject.handleResponseText(text);
} else {
- // shell.error.setInnerText(SERVER_ERROR + " ("
- // + response.getStatusText() + ")");
+ logger.severe(SERVER_ERROR + " (" + response.getStatusText()
+ ")");
}
postRequestEvent(State.RECEIVED, response);
}
@@ -75,11 +83,11 @@
});
try {
+ logger.finest("Sending fire request");
builder.send();
postRequestEvent(State.SENT, null);
} catch (RequestException e) {
- // shell.error.setInnerText(SERVER_ERROR + " (" + e.getMessage() +
- // ")");
+ logger.log(Level.SEVERE, SERVER_ERROR + " (" + e.getMessage()
+ ")", e);
}
}
@@ -106,27 +114,27 @@
public void onError(Request request, Throwable exception) {
postRequestEvent(State.RECEIVED, null);
- // shell.error.setInnerText(SERVER_ERROR);
+ logger.log(Level.SEVERE, SERVER_ERROR, exception);
}
public void onResponseReceived(Request request, Response
response) {
+ logger.finest("Response received");
if (200 == response.getStatusCode()) {
// parse the return value.
receiver.onSuccess(jsonDeltas.commit(response.getText()));
} else {
- // shell.error.setInnerText(SERVER_ERROR + " ("
- // + response.getStatusText() + ")");
+ logger.severe(SERVER_ERROR + " (" + response.getStatusText()
+ ")");
}
postRequestEvent(State.RECEIVED, response);
}
});
try {
+ logger.finest("Sending sync request");
builder.send();
postRequestEvent(State.SENT, null);
} catch (RequestException e) {
- // shell.error.setInnerText(SERVER_ERROR + " (" + e.getMessage()
+
- // ")");
+ logger.log(Level.SEVERE, SERVER_ERROR + " (" + e.getMessage()
+ ")", e);
}
}
@@ -143,6 +151,16 @@
protected void init(HandlerManager handlerManager, RecordToTypeMap map) {
this.valueStore = new ValueStoreJsonImpl(handlerManager, map);
this.handlerManager = handlerManager;
+ // This Handler should really get added to the Root Logger here, but
until
+ // App Engine Dev Mode logging is fixed, we can't use client side
handlers
+ // on the Root Logger. Instead, just add it to our own logger as a
proof of
+ // concept, and then log a Severe message to it to prove that it's
working
+ // All the "finest" messages that this class normally logs are not
logged
+ // to this handler since it would cause an infinite loop.
+ // TODO(unnurg): Once this is all set up, ensure that the severe
messages
+ // in this class do not cause infinite loops during legitimate errors.
+ logger.addHandler(new RequestFactoryLogHandler(this));
+ logger.severe("Successful initialization!");
}
private void postRequestEvent(State received, Response response) {
=======================================
---
/trunk/user/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
Fri Jul 23 15:42:40 2010
+++
/trunk/user/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
Mon Jul 26 15:35:20 2010
@@ -267,6 +267,17 @@
}
requestSelectors.add(method);
}
+
+ // In addition to the request selectors in the generated interface,
there
+ // are a few which are in RequestFactory which also need to have
+ // implementations generated. Hard coding the addition of these here
for now
+ JClassType t = generatorContext.getTypeOracle().findType(
+ RequestFactory.class.getName());
+ try {
+ requestSelectors.add(t.getMethod("loggingRequest", new JType[0]));
+ } catch (NotFoundException e) {
+ e.printStackTrace();
+ }
// write init()
JClassType recordToTypeInterface =
generatorContext.getTypeOracle().findType(
@@ -368,8 +379,8 @@
packageName, implName);
f.addImport(ClientRequestHelper.class.getName());
f.addImport(RequestDataManager.class.getName());
-
- f.addImplementedInterface(selectorInterface.getName());
+ f.addImport(mainType.getQualifiedSourceName() + "Impl");
+ f.addImplementedInterface(selectorInterface.getQualifiedSourceName());
SourceWriter sw = f.createSourceWriter(generatorContext, out);
sw.println();
=======================================
---
/trunk/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java
Thu Jun 24 14:48:00 2010
+++
/trunk/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java
Mon Jul 26 15:35:20 2010
@@ -91,5 +91,13 @@
void init(HandlerManager eventBus);
+ // The following methods match the format for the generated
sub-interfaces
+ // and implementations are generated using the same code we use to
generate
+ // those. In order to ensure this happens, each of the request selectors
+ // needs to be manually added to the requestSelectors list in
+ // RequestFactoryGenerator.java
+ LoggingRequest loggingRequest();
+
SyncRequest syncRequest(DeltaValueStore deltaValueStore);
-}
+
+}
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors