===== Accesso Diretto Risorse (DAR) ===== In Geoweb la funzionalità **DAR** (**Direct Access Resource**), introdotta con la //versione 4.6.5//, permette di implementare l'accesso automatico diretto ad una qualsiasi risorsa, tramite **link URL**. ==== Definizione di Risorsa ==== E’ una qualsiasi tipo di scheda (o componente di UI) apribile tramite le api javascript di Geoweb. Esempi: - gwClassList, lista di classe, eventualmente prefiltrata - gwClassDetail, dettaglio di classe - layout2D, scheda mappa con uno o più oggetti selezionati, e con eventuali filtri sui layer - ... - combinazioni di risorse: lista+dettaglio, etc.. In questo documento si parla esclusivamente di risorse erogabili nell'ambito del gwProject. Altri tipi di risorsa, per esempio documenti ospitati nei documentali, possono essere scaricati tramite link diretto, costruendolo secondo le specifiche api. ==== Casi d'uso ==== L'ambito di utilizzo principale, è per generare url che puntano a determinate risorse da utilizzare nella creazione automatica di email e notifiche utente. Di recente la funzionalità DAR è stata anche utilizzata come base per il funzionamento del widget indirectLocalizationWidget. **Alla luce delle future implementazioni si suggerisce di predisporre l'infrastruttura delle tabelle DAR in ogni nuova implementazione di Prodotto/Progetto. Per i porting di vecchie installazioni alla versione 4.6.x si dovrà invece valutare caso per caso** ==== Descrizione funzionamento ==== L'apertura della risorsa viene materialmente effettuata tramite l'invocazione di una **function javascript**, disponibile nel **namespace globale**. La function viene eseguita al momento opportuno, durante le fasi di apertura del progetto. Il nome della funzione, i parametri con cui essa deve essere invocata, e il progetto di riferimento sono racchiusi in un oggetto di tipo **DAR**, che viene persistito sul database, e a cui si fa riferimento tramite un **id criptato**. ==== Parametro dar ==== L'apertura di una data risorsa è attuata tramite l'introduzione di un nuovo parametro: **dar**, opzionale, da aggiungere nel //queryString// dell'url del gwProject. **dar** rappresenta l'identificativo criptato dell'oggetto DAR censito sul database (Es: 'dar=sqsUQ14rLb4nknbNMUmOyNvIG76xmxkeYJfhKcp0Abc'). Esempio url: http://localhost:8081/webclient/project/base_ut.html?group=TESTER_GROUP&preventCache=1686735011463&dar=sqsUQ14rLb4nknbNMUmOyNvIG76xmxkeYJfhKcp0Abc ==== Generazione URL ==== L'url di progetto può essere generato tramite l'apposito service //DirectAccessResourceService//, esposto nei .groovy come **darService**. Questo espone tutta una serie di metodi di utilità. Il metodo più generale per censire un DAR dal groovy, ed ottenerne il relativo url è: public String generateDARFromDARParts(String functionName, String jsonParam, String gwProjectName, Map queryParameterMap) Utilizzabile cosi: String functionName = "alert"; def params = "alert message"; String gwProjectName = "base_ut"; Map queryParameterMap = null; String url = services.darService.generateDARFromDARParts(functionName, params, gwProjectName, queryParameterMap); String functionName = "openGwClassDetail"; def itemId = 19; def gwClassName = "utc"; def gwClassDetailOptions = [:]; gwClassDetailOptions.openingDetailMode = "tab"; Map params = [itemId, gwClassName, gwClassDetailOptions]; String gwProjectName = "base_ut"; Map queryParameterMap = [:]; queryParameterMap.group = "group"; queryParameterMap.gwp = "vIG76xmxkeYJfhKcp0AbcsqsUQ14rLb4nknbNMUm"; String url = services.darService.generateDARFromDARParts(functionName, params, gwProjectName, queryParameterMap); In generale si specifica la funzione da eseguire, i relativi parametri ed il progetto di contesto. Inoltre si possono specificare una mappa di ulteriori parametri che si desidera vadano nell'url per utilizzare altre funzionalità del framework, come: - imposizione oggetto in sessione - imposizione gruppo (scelto in automatico, se assente) - imposizione ambito (scelto in automatico, se assente) === Parametri funzione === Venendo i parametri riversati in automatico al momento dell'invocazione delle function, sono validi tutti i parametri supportati dalla funzione medesima. Ne deriva che, utilizzando come function una api js specifica, se ne possono utilizzare con successo anche tutti i relativi parametri. I parametri verranno semopre passati come array alle funzioni. nel caso il parametro in ingresso sia una mappa, verrà incapsulato in automatico come primo elemento di un array. Questo anche perchè alcune api js preesistenti prevedevano più parametri (es: openGwClassDetail()) Cosi viene garantita la massima flessibilità. L'unica accortezza è nel caso, si utilizzi una function il cui primo parametro ammesso è a sua volta un array, è quello di pre-incapsularlo in un altro array, seguito dagli eventuali altri: === metodi specializzati === Esistono dei metodi specializzati per generare url per i casi più comuni. Questi settano in automatico il //functionName// e calcolano in automatico il path di navigazione sui tre livelli (vedi sotto). Elenco: //apertura lista public String generateDAROpenGwClassListTab(Map params, String gwProjectName, Map queryParameterMap) //apertura scheda lista+dettaglio public String generateDAROpenGwClassListTabAndGwClassDetail(Map params, String gwProjectName, Map queryParameterMap) //esecuzione leafItemAction public String generateDARExecuteLeafItemAction(Map params, String gwProjectName, Map queryParameterMap) //apertura scheda Layout2D public String generateDAROpenLayout2DTab(Map params, String gwProjectName, Map queryParameterMap) //apertura scheda report html public String generateDAROpenGwHtmlReport(Map params, String gwProjectName, Map queryParameterMap) //generazione del solo url public String buildURL(DAR dar, Map queryParameterMap) Questi metodi hanno come controparte javascript i seguenti metodi predefiniti che, oltre a ricalcare la api js di base, si occupano anche di provare a selezionare il path di navigazione sui tre livelli di menu. - function openGwClassListTabDAR(params) - function openGwClassListTabAndGwClassDetailDAR(params) - function openGwClassListTabAndGwClassDetailFloatingPaneDAR(params) - function openGwClassListTabAndGwClassDetailDialogDAR(params) - function openGwClassListTabAndGwClassDetailTabDAR(params) - function executeLeafItemActionDAR(params) - function openLayout2DTabDAR(params) - function openGwHtmlReportDAR(params) === altri metodi === Altri metodi, di carattere generale. Non dovrebbero servire nei groovy, ma si elencano per completezza. public Integer insertDAR(DAR dar) public Integer updateDAR(DAR dar) public Integer deleteDAR(DAR dar) public DAR selectById(Integer darId) public DAR selectByIdEnc(String darIdEnc) public ArrayList selectAll() public ArrayList selectAllByGwProject(String gwProjectName) public ArrayList selectAllByFunctionName(String functionName) public String generateDARFromDARParts(String functionName, String jsonParam, String gwProjectName) public String generateDARFromDARParts(String functionName, String jsonParam, String gwProjectName, Map queryParameterMap) { public String generateDAR(DAR dar) public String generateDAR(DAR dar, Map queryParameterMap) ==== Esempi di utilizzo comune (generazione url da groovy) ==== === Apertura scheda gwClassList === String gwProjectName = "gwProjectName"; Map params = [:]; params.gwClassName = "utc"; Map queryParameterMap = null; String url = services.darService.generateDAROpenGwClassListTab(params, gwProjectName, queryParameterMap); String gwProjectName = "gwProjectName"; Map params = [:]; params.gwClassName = "utc"; params.staticFilters= [[condition: "AND", columnName: "field", operator: "=", value: "a"]]; Map queryParameterMap = null; String url = services.darService.generateDAROpenGwClassListTab(params, gwProjectName, queryParameterMap); === Apertura scheda gwClassList + gwClassDetail === apertura tab Map params = [:]; params.gwClassName = "utc"; params.itemId= "19"; def gwClassListOptions = [:]; params.gwClassListOptions = gwClassListOptions ; def gwClassDetailOptions = [openingDetailMode: "tab"]; params.gwClassDetailOptions = gwClassDetailOptions ; String gwProjectName = "base_ut"; Map queryParameterMap = null; String url = services.darService.generateDAROpenGwClassListTabAndGwClassDetail(params, gwProjectName, queryParameterMap); Map params = [:]; params.gwClassName = "utc"; params.itemId= "19"; def gwClassListOptions = [staticFilters: [[condition: "AND", columnName: "field", operator: "=", value: "a"]] ]; params.gwClassListOptions = gwClassListOptions ; def gwClassDetailOptions = [openingDetailMode: "floatingPane", detailLayoutName: "textbox", hideTopToolbar: true]; params.gwClassDetailOptions = gwClassDetailOptions ; String gwProjectName = "base_ut"; Map queryParameterMap = null; String url = services.darService.generateDAROpenGwClassListTabAndGwClassDetail(params, gwProjectName, queryParameterMap); === Apertura scheda Layout2D === mappa cartografica Map params = [:]; params.gwMapName = "sites"; String gwProjectName = "base_ut"; Map queryParameterMap = null; String url = services.darService.generateDAROpenLayout2DTab(params, gwProjectName, queryParameterMap); planimetria, filtrata, e selezione multipla in mappa Map params = [:]; params.gwMapName = "mappa_asset"; params.drawingSetId= 12345; params.classNameToItemIdListMap= [asm_asset: [456, 789]]; params.geometryColumn = "mainGeom"; params.saveMapSelection = true; gwLayerNameToStaticFiltersMap = [asset: [[ … operato: "=", value: "ACTIVE"]]]; String gwProjectName = "base_ut"; Map queryParameterMap = null; String url = services.darService.generateDAROpenLayout2DTab(params, gwProjectName, queryParameterMap); === Apertura scheda reportHTML === Map params = [:]; params.reportUrl = "reportUrl"; params.gwClassName = "gwClassName"; params.reportParameters = [p1: "v1", p2: 2, p3: true]; params.updateOnChangeInGwClassNameList = "gwClassName1,gwClassName2"; String gwProjectName = "base_ut"; Map queryParameterMap = null; String url = services.darService.generateDAROpenGwHtmlReport(params, gwProjectName, queryParameterMap); === Apertura scheda da leafItem gwAction === A volte una risorsa è aperta tramite gwAction configurata nell'xml di progetto. Per usare i medesimi meccanismi è previsto l'apposito metodo esposto. Non è previsto il passaggio di parametri alla gwAction di classe (in quanto autoconsistente). Nel caso fosse necessario il passaggio di parametri sarebbe opportuno creare una function custom ed invocare l'api generale nel groovy. Map params = [:]; params.gwClassName = "gwClassName "; params.gwActionName = "gwActionName "; String gwProjectName = "base_ut"; Map queryParameterMap = null; String url = services.darService.generateDARExecuteLeafItemAction(params, gwProjectName, queryParameterMap); ==== Caso generale ==== Qualora fosse necessario implementare comportamenti fuori dallo standard nell'atto di erogare una risorsa i passaggi da seguire sarebbero i seguenti: - individuare una function js predefinita che venga definita nel DAR. In caso contrario definirla in un plugin di prodotto/commessa - generare il DAR utilizzando l'api java generale ==== Selezione automatica 3-level menu ==== Ove possibile, qualora la risorsa richiesta sia dichiarata nella struttura dell'xml di progetto, verrà coerentemente selezionato il path di navigazione dei 3 livelli di menu. Questo avviene tramite un controllo di matching fra la tipologia di scheda ed gli eventuali parametri aggiuntivi. Più parametri saranno aggiunti e più restrittivo diventerà il criterio di matching. Per esempio dato un url, con dar generato tramite generateDAROpenGwClassListTab(), senza definire ulteriori parametri per la gwClassList, verrà selezionata in automatico, se trovata, la prima voce di menu che avrà //gwClassList// per //leafItem type// e il cui parametro //gwClassName// sarà il medesimo referenziato dal dar. Specificare ulteriori parametri per la gwClassList nel dar, causerà l'aggiunta di ulteriori criteri nella ricerca nella struttura dell'xml di progetto. Ci potrebbero essere casi in cui i parametri del dar, potrebbero essere definiti in più punti della struttura xml di progetto. Per esempio dar generati con generateDAROpenGwClassListTab() senza parametri e più voci leafItem gwClassList con differenti filtri statici nell'xml di progetto. In questo caso è utile utilizzare il parametro **navCoords**, che forza la selezione sui tre livelli di menu, evitando l'autoretrieve del path, che selezionerebbe la prima voce corrispondente ai pochi criteri. Da notare che la risorsa verrà aperta sempre e solo utilizzando i parametri specificati nel DAR, e non gli ulteriori eventualmente specificati nell'xml di progetto. === Note selezione automatica 3-level menu ==== La selezione è supportata per le azioni gwAction presenti nell'xml di progetto [java generateDARExecuteLeafItemAction()+js executeLeafItemActionDAR()]. Per altre azioni generiche, non verrà fatta la selezione automatica a meno che non si forzi il parametro **navCoords**, nel primo o nell'ultimo (per flessibilità di utilizzo) oggetto dell'array di parametri con cui viene invocata la funzione ==== Integrazione con altri sviluppi ==== Questa funzionalità si lega a sviluppi paralleli, come quello del sistema di eventi e notifiche. In particolare si vorrebbe permettere all’utente di accedere direttamente la risorsa oggetto della notifica, tramite url. Fin da ora potrebbe già essere configurato per una più potente e diretta navigazione fra le risorse delle funzioni ==== configuration.properties ==== L’url verrà costruito sulla base di un base url, recuperato dal **configuration.properties** dal nuovo parametro introdotto per l’occasione: **baseUrl**. ################################################################## # B A S E U R L ################################################################## baseUrl=http://localhost:8081/webclient Nella issue **issue #1463** si è abilito il supporto nel configuration.properties al parametro **info.link_web**, che se presente, prevale sul **baseUrl**. Ecco la logica di utilizzo per generare l'url. //URL example: // http://localhost:8081/webclient/project/base_ut.html?group=TESTER_GROUP&preventCache=1686735011463&dar=sqsUQ14rLb4nknbNMUmOyNvIG76xmxkeYJfhKcp0Abc //Diamo precedenza al parametro info.link_web (issue #1463) String baseUrl = ConfigurationProperties.getInstance().getString("info.link_web", null); //se il parametro info.link_web è nullo, consideriamo il baseUrl come prima (issue #1463) if(baseUrl==null || baseUrl.trim().isEmpty()) { baseUrl = ConfigurationProperties.getInstance().getString("baseUrl", null); if (baseUrl==null || baseUrl.trim().isEmpty()) throw new RuntimeException("Missing or empty the required parameter in configuration.properties 'baseUrl'! Missing or empty the parameter 'info.link_web' parameter too (searched and used with priority upon 'baseUrl')!"); } if(!baseUrl.endsWith("/")) baseUrl += "/"; url = baseUrl+"project/"+gwProjectName+".html?"; ==== Nozioni Tecniche Aggiuntive==== === Modello dati === A supporto della nuova funzionalità è prevista la creazione di una nuova tabella sullo **schema dati**: **gw_dar**. {{ :custom:gw_dar_db_model.png |}} Dettaglio campi: - **dar_id**: integer, required, chiave primaria per la tabella e identificativo della dar - **function_name**, string, required. Nome della funzione, disponibile nel namespace (direttamente nel framework o da qualche plugin), contenente il codice necessario per l’apertura della risorsa (tipicamente un’invocazione diretta delle api javascript esposte) - **json_param**, string, optional, default null. Stringa in formato JSON contenente eventuali parametri di ingresso da fornire alla function js. Qui andrebbe anche un parametro, opzionale, che se configurato può essere usato per replicare l’apertura, previa navigazione, da parte di una scheda configurata nell’xml di progetto (in sua assenza si tenterebbe comunque di ricostruire il path di navigazione, in maniera automatica, ma non sempre funzionante): - **navCoords**: Integer[], contenente gli indici delle voci di menu rispettivamente del 1st, del 2nd e del 3rd level menu. Per esempio [2,0,1] - **gw_project_name**, string, required. Name del gwProject su cui dovrà essere eseguita la function. Introdotto per motivi di sicurezza: al momento dell’esecuzione della function verrà eseguito un check di consistenza del projectName. - **dar_id_enc**: string, auto-calcolato sulla base di dar_id, con chiave simmetrica (AES/CBC/PKCS5PADDING). Viene fatta anche la codifica URL. Minima lunghezza: 43 char, che può crescere coerentemente con le dimensioni del dar_id da cifrare - **dar_url**: string, auto-calcolato sulla base di gw_project_name, di dar_id_enc e degli altri eventuali valori da inserire nel queryString dell’URL. - **dar_date**: date, autocalcolato sulla data computazione del dar_url === script Oracle === CREATE TABLE "xxx_data"."gw_dar" ( "dar_id" NUMBER(*,0) NOT NULL ENABLE, "function_name" VARCHAR2(400 BYTE) NOT NULL ENABLE, "json_param" VARCHAR2(4000 BYTE) NOT NULL ENABLE, "gw_project_name" VARCHAR2(250 BYTE) NOT NULL ENABLE, "dar_id_enc" VARCHAR2(400 BYTE), "dar_url" VARCHAR2(4000 BYTE), "dar_date" date, CONSTRAINT "GWdar_PKEY" PRIMARY KEY ("dar_id") ); === script Postgres === CREATE TABLE IF NOT EXISTS xxx_data.gw_dar ( dar_id integer NOT NULL, function_name character varying COLLATE pg_catalog."default" NOT NULL, json_param character varying COLLATE pg_catalog."default" NOT NULL, gw_project_name character varying COLLATE pg_catalog."default" NOT NULL, dar_id_enc character varying COLLATE pg_catalog."default", dar_url character varying COLLATE pg_catalog."default", dar_date timestamp without time zone, CONSTRAINT gw_dar_pkey PRIMARY KEY (dar_id) ) WITH ( OIDS = FALSE ) TABLESPACE pg_default; ALTER TABLE xxx_data.gw_dar OWNER to xxx_data; === script MS Sqlserver=== CREATE TABLE [xxx_data].[gw_dar] ( [dar_id] [int]IDENTITY(1,1) NOT NULL, [function_name] [varchar](400), [json_param] [varchar](MAX), [gw_project_name] [varchar](250), [dar_id_enc] [varchar](400), [dar_url] [varchar](max), [dar_date] [datetime], CONSTRAINT [gw_dar_pkey] PRIMARY KEY (dar_id) ); === Metadati gwClass gw_dar === Metadati utilizzati per l'ambiente di test ed utili per la gestione della anagrafica DAR. {{ :custom:dar_metadata.zip|Tema DAR e classe gw_dar (.zip)}}