remoto procedimiento llamada groove error 0x800706be gwt gwt-rpc

gwt - procedimiento - error en la llamada sql server



GWT, ¿cómo puedo reducir el tamaño de los serializadores de código para llamadas RPC? (5)

Para cualquier servicio GWT-RPC, GWt generará un Proxy, un TypeSerializer. Y para cada objeto que posiblemente se pueda pasar a través de GWT, tendrá una clase FieldSerializer. Y solo puede haber un FieldSerializer por clase. Por lo tanto, no hay forma de que pueda tener dos FieldSerializers para un AccountDTO.

La regla de enlace diferido que intentas usar no funcionará. Por ejemplo, tiene algo como esto: MyServiceAsync sync = GWT.create (MyService.class);

Las reglas de enlace diferido lo cambiarán a:

MyServiceAsync sync = new MyServiceAsync_Proxy ();

Tus reglas realmente harán algo como esto:

MyServiceAsync sync = new MyGenericService (); // no válido, ya que MyGenericService es una interfaz

Entonces tu solución no funcionará

Como dice que el 60% del código generado por la aplicación está relacionado con RPC, sospecho que tiene un problema de explosión del tipo RPC.

Compruebe si GWT no arroja advertencias durante la compilación, o genera stubs para RPC TypeSerializers, lo más probable es que tenga una interfaz muy común en el servicio.

Descubrí que más del 60% del código javaScript generado por GWT en mi aplicación es para los serializadores RPC. También encontré que los serializadores no se comparten entre las interfaces de servicio, es decir, si tengo, por ejemplo, el tipo AccountDTO al que se hace referencia en 2 interfaces de servicio rpc, obtendré 2 clases de serializador en lugar de 1 para el mismo tipo. Para reducir el tamaño del código compilado, estaba pensando que tal vez podría utilizar la vinculación diferida para reemplazar todas las interfaces de servicios que tengo para una gran interfaz. Si eso fuera posible, quizás entonces GWTCompiler producirá solo un serializador AccountDTO en lugar de 2.

No estoy seguro de si esta es una buena idea o si hay una solución mejor para mi problema.

Lo que estaba tratando de implementar fue algo como esto:

// Define new interface that extends all service interfaces public interface GenericService extends RemoteService, AccountingService, FinancialService,..., { } public interface GenericServiceAsync extends AccountingServiceAsync, FinancialServiceAsync, ..., { } // At Application.gwt.xml do: <module> ... ... <replace-with class="com.arballon.gwt.core.client.GenericService"> <when-this-is class="com.arballon.gwt.core.client.AccountingService> </replace-with> <replace-with class="com.arballon.gwt.core.client.GenericService"> <when-this-is class="com.arballon.gwt.core.client.FinancialService> </replace-with> ... ...

Pero en este momento estaba recibiendo el error:

[ERROR] Errores en ''archivo: / C: /Users/Daniel/EclipseWorkspace/ADK/src/com/arballon/gwt/core/client/FinancialService.java'' [ERROR] Línea 31: Reenlace resultado ''com.arballon.gwt .core.client.GenericService ''no se pudo encontrar

Cualquier idea sobre el tema será apreciada. Saludos

Daniel


Por lo que yo entiendo, se supone que la generación de código GWT proporciona implementaciones concretas de una interfaz. Esta implementación se transforma luego en javascript para permutaciones específicas.

Su muestra, por otro lado, está reemplazando una interfaz con la otra. Si lo ves desde los ojos del compilador de GWT, quizás veas el problema con esta configuración.

Supongamos que usted es el compilador GWT y ve la siguiente línea en el código del lado del cliente que está convirtiendo en JavaScript

AccountingServiceAsync accountingServiceAsync = (AccountingServiceAsync) GWT.create(AccountingService.class); accountingServiceAsync.recordTransaction(transaction,callback);

Por lo tanto, debe averiguar qué sucederá en la línea 2. Específicamente, debe saber dónde encontrar la implementación de accountingServiceAsync.recordTransaction (). Entonces, busca en toda su configuración para encontrar si existe una regla que especifique qué clase de implementación se debe usar para AccountingService (no Async). Pero lamentablemente no encuentras ninguno. Pero luego observa que AccountingService es también un RemoteService. Entonces vuelves a sumergirte en tu configuración. Y, aha, ahí está, una regla que especifica que puede generar implementaciones de RemoteService con ServiceInterfaceProxyGenerator . Con gusto entregará la tarea de proporcionar una implementación de AccountingService a ServiceInterfaceProxyGenerator.

Pero supongamos que en lugar de este final feliz, su configuración le dice que AccountingService puede ser reemplazado por GenericService, y usted dice "hey cool, bring it on". Pero justo entonces descubres que GenericService también es una interfaz. Claramente, se apagará, diciendo "ahora, ¿qué voy a hacer con otra interfaz? Todo lo que necesitaba era una implementación de AccountingService". En este punto, querrá desquitarse con el programador lanzándole un error críptico.

Entonces, todo esto explica por qué su solución (teóricamente) no funcionará. En cuanto a su preocupación real de javascript hinchado, estoy sorprendido de que este problema exista incluso dada la cantidad de esfuerzo que la gente de GWT pone en la optimización del JavaScript compilado. ¿Cómo evaluaste tu salida compilada para duplicar?


El código de generación RPC de GWT crea varias clases para hacer su trabajo como lo ha notado: un *_FieldSerializer para cada tipo que pasa por el cable, y una clase *_Proxy para el tipo de async de RemoteService. Ese tipo de proxy requiere un *_TypeSerializer , que es la raíz de su problema: por alguna razón, GWT conecta todos los métodos de serialización / deserialización en un mapa de funciones string-> js, probablemente para facilitar las búsquedas rápidas, pero este código de configuración viene a costa de líneas de código que deben estar en la compilación final. Un enfoque más optimizado podría hacer que cada FieldSerializer tenga un método de registro donde agregue sus métodos al mapa estático propiedad del Proxy - esto está plagado, sin embargo, pero la optimización de GWT de intentar no hacer referencia a instantiate() , deserialize() y serialize() métodos si no aparece serán llamados.

Su problema radica en tener muchos tipos que se pueden serializar, y en haber intentado crear tipos de RemoteService que describan unidades específicas de funcionalidad, pero que reutilicen muchos tipos de modelos. Objetivo admirable, especialmente porque probablemente hará que su código de servidor se vea mejor, pero aparentemente GWT lo muerde por ello.

La solución que intenté ofrecerle en freenode (como niloc132) fue construir un solo tipo de RemoteService grande, al que denominó GeneralService , y un GeneralServiceAsync coincidente, cada uno extendiendo todos los tipos de servicio rpc existentes. Lo primero que pensé fue usar un <replace-with> para decirle al sistema del generador que cuando desee que cada tipo de RemoteService lo reemplace con GeneralService , pero como señala Tahir, esto no tiene sentido: GWT no pasa los resultados de la nueva unión. de nuevo en sí mismo para seguir haciendo búsquedas. En cambio, sugeriría que cuando desee un tipo de servicio asíncrono, haga lo siguiente:

AccountingServiceAsync service = (AccountingServiceAsync) GWT.create(GeneralService.class)

El resultado de volver a GeneralService de GeneralService implementará GeneralServiceAsync , que a su vez se puede asignar a AccountingServiceAsync . Si la memoria le sirve, dijo que tiene métodos / campos estáticos que brindan estos servicios: cambie esos sitios para crear siempre una instancia de GeneralServiceAsync . Siempre que no invoque GWT.create en ningún subtipo de Servicio GWT.create sino GeneralService , limitará el número de TypeSerializers a uno.

Como nota al margen, los subtipos de RemoteServiceProxy son sin estado, por lo que asegurarse de crear solo una instancia puede facilitar la compilación de forma coherente, pero no ahorra memoria ni tiempo en el tiempo de ejecución, ya que casi con seguridad se compilan en métodos estáticos. Sin embargo, las clases *_TypeSerializer tienen estado, pero solo hay una instancia de cada una, por lo que la combinación de todos sus Servicios RemoteService podría ahorrar una cantidad muy pequeña de memoria de trabajo.


Bueno, después de un par de viajes de ida y vuelta finalmente encontramos una solución a nuestro problema, quiero compartirla en caso de que pueda ayudar a otros. Primero debo mencionar la ayuda de Colin Alworth, sin su apoyo esta solución no sería posible en absoluto. También debo mencionar que no estoy realmente orgulloso de la solución final, pero funciona para nosotros y por el momento es lo mejor que tenemos.

Lo que finalmente hicimos fue, como observa Colin en la última publicación, reemplazar el GWT.create de cada una de nuestras interfaces de servicio para crear en su lugar la interfaz GenericBigService.

Así que nuestro primer parche es así:

1) Cree la interfaz GenericBigService que amplía todas las interfaces de servicio que tenemos (actualmente 52 interfaces), y también crea su hermano Async. lo hicimos a través de un script phytom.

Entonces nuestra GenericBigInterface se ve así:

package com.arballon.gwt.core.client; import com.google.gwt.user.client.rpc.RemoteService; public interface GenericBigService extends RemoteService, AccountingService, ActionClassifierService, AFIPWebService, AnalyticalService, AuthorizationService, BudgetService, BusinessUnitService, CatalogPartService, CategoryService, ClientDepositService, ..... ..... { }

2) Tenemos una clase estática interna Util en cada interfaz de Servicio para instanciar la instancia de Async, allí reemplazamos GWT.create para crear GenericBigInterface.

Una de nuestras interfaces de servicio se ve así:

public interface FinancialPeriodBalanceCategoryService extends RemoteService { /** * Utility class for simplifying access to the instance of async service. */ public static class Util { private static FinancialPeriodBalanceCategoryServiceAsync instance; public static FinancialPeriodBalanceCategoryServiceAsync getInstance() { if (instance == null) { instance = GWT.create(GenericBigService.class); ((ServiceDefTarget)instance).setServiceEntryPoint(GWT.getModuleBaseURL()+"FinancialPeriodBalanceCategoryService"); } return instance; } }

tenemos que hacer la llamada serServiceEntyPoint para mantener nuestro web.xml sin modificaciones.

Cuando compilamos por primera vez, compila bien, pero no funciona porque en el tiempo de ejecución, la llamada al servidor arroja una excepción:

IncompatibleRemoteServiceException Blocked attempt to access interface GenericBigService

, que no está implementado por FinancialPeriodBalanceCategoryService

Bueno, eso fue absolutamente correcto. Estamos llamando al servicio con una interfaz que no implementa, y aquí es cuando aparece la parte fea. No pudimos encontrar el momento mejor solución que podamos codificar, que la que decidimos implementar eso es:

Reemplazamos RPC.java con nuestra propia copia y reemplazamos el código de esta manera:

en el método decodeRequest que hicimos:

if (type != null) { /*if (!implementsInterface(type, serviceIntfName)) { // The service does not implement the requested interface throw new IncompatibleRemoteServiceException( "Blocked attempt to access interface ''" + serviceIntfName + "'', which is not implemented by ''" + printTypeName(type) + "''; this is either misconfiguration or a hack attempt"); }*/ if (!implementsInterface(type, serviceIntfName)) { if(!serviceIntfName.contains("GenericBigService")){ throw new IncompatibleRemoteServiceException( "Blocked attempt to access interface ''" + serviceIntfName + "'', which is not implemented by ''" + printTypeName(type) + "''; this is either misconfiguration or a hack attempt"); } }

El beneficio de hacer esto fue:

1) fuimos a tomar 1 hora y 20 minutos para compite para tomar solo 20 minutos para 6 permutariones.

2) En devMode, todo comienza a ejecutarse más rápidamente. El inicio sigue siendo más o menos el mismo, pero la ejecución una vez que comienza va realmente bien.

3) La reducción en el tamaño de la compilación fue otro resultado interesante no menor, reducimos el segmento sobrante de 6Mb a 1.2Mb, reducimos la compilación completa de tamaño JS en aprox. 50% a 60%.

Estamos muy contentos con GWT-RPC y no queremos dejarlo, pero TypeSerializers fue realmente un problema básicamente debido al tamaño del JS que resulta. Con esta solución, sé que no es muy elegante pero funciona, y funciona bien. Gracias de nuevo Colin por tu ayuda!

Saludos Daniel


Si desea tener una mejor solución, ¿por qué no utilizar un patrón de comando? de esta forma solo necesita un servicio GWT que acepte un subtipo Command y devuelva un subtipo Result (puede hacer que sea seguro mediante el uso de genéricos).

Lo bueno es que solo necesita declarar un método en un servlet gwt y desde allí puede enviarlo a cualquier otro servicio del lado del servidor.

El patrón de comando también puede brindarle muchos beneficios adicionales, ya que tiene un punto de control central para realizar comprobaciones de seguridad o le permite realizar solicitudes de lotes transparentes.

Su exposición a GWT se vuelve mucho más pequeña en el lado del servidor.