PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/backend/src/main/java/com/gooddata/integration/rest/GdcRESTApiWrapper.java

https://github.com/chrbayer84/GoodData-CL
Java | 3612 lines | 2682 code | 258 blank | 672 comment | 638 complexity | bb3f18c8650bfde5a04dfb923f1c73d6 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2009, GoodData Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without modification, are permitted provided
  5. * that the following conditions are met:
  6. *
  7. * * Redistributions of source code must retain the above copyright notice, this list of conditions and
  8. * the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  10. * and the following disclaimer in the documentation and/or other materials provided with the distribution.
  11. * * Neither the name of the GoodData Corporation nor the names of its contributors may be used to endorse
  12. * or promote products derived from this software without specific prior written permission.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  15. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  16. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  19. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  20. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  21. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. package com.gooddata.integration.rest;
  24. import com.gooddata.Constants;
  25. import com.gooddata.exception.*;
  26. import com.gooddata.integration.model.Column;
  27. import com.gooddata.integration.model.Project;
  28. import com.gooddata.integration.model.SLI;
  29. import com.gooddata.integration.rest.configuration.NamePasswordConfiguration;
  30. import com.gooddata.util.FileUtil;
  31. import com.gooddata.util.NetUtil;
  32. import net.sf.json.JSON;
  33. import net.sf.json.JSONArray;
  34. import net.sf.json.JSONObject;
  35. import org.apache.commons.httpclient.HttpClient;
  36. import org.apache.commons.httpclient.HttpException;
  37. import org.apache.commons.httpclient.HttpMethod;
  38. import org.apache.commons.httpclient.HttpStatus;
  39. import org.apache.commons.httpclient.cookie.CookiePolicy;
  40. import org.apache.commons.httpclient.methods.DeleteMethod;
  41. import org.apache.commons.httpclient.methods.GetMethod;
  42. import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
  43. import org.apache.commons.httpclient.methods.PostMethod;
  44. import org.apache.commons.httpclient.methods.PutMethod;
  45. import org.apache.commons.lang.StringUtils;
  46. import org.apache.log4j.Logger;
  47. import java.io.ByteArrayInputStream;
  48. import java.io.IOException;
  49. import java.io.UnsupportedEncodingException;
  50. import java.net.MalformedURLException;
  51. import java.net.URL;
  52. import java.nio.charset.Charset;
  53. import java.util.*;
  54. import java.util.regex.Matcher;
  55. import java.util.regex.Pattern;
  56. /**
  57. * The GoodData REST API Java wrapper.
  58. *
  59. * @author Zdenek Svoboda <zd@gooddata.org>
  60. * @version 1.0
  61. */
  62. public class GdcRESTApiWrapper {
  63. private static Logger l = Logger.getLogger(GdcRESTApiWrapper.class);
  64. /**
  65. * GDC URIs
  66. */
  67. private static final String PLATFORM_URI = "/gdc/";
  68. private static final String MD_URI = "/gdc/md/";
  69. private static final String LOGIN_URI = "/gdc/account/login";
  70. private static final String DOMAIN_URI = "/gdc/account/domains";
  71. private static final String DOMAIN_USERS_SUFFIX = "/users";
  72. private static final String PROJECT_USERS_SUFFIX = "/users";
  73. private static final String PROJECT_ROLES_SUFFIX = "/roles";
  74. private static final String TOKEN_URI = "/gdc/account/token";
  75. private static final String DATA_INTERFACES_URI = "/ldm/singleloadinterface";
  76. private static final String PROJECTS_URI = "/gdc/projects";
  77. private static final String PULL_URI = "/etl/pull";
  78. private static final String IDENTIFIER_URI = "/identifiers";
  79. private static final String SLI_DESCRIPTOR_URI = "/descriptor";
  80. public static final String MAQL_EXEC_URI = "/ldm/manage";
  81. public static final String MAQL_ASYNC_EXEC_URI = "/ldm/manage2";
  82. public static final String DML_EXEC_URI = "/dml/manage";
  83. public static final String PROJECT_EXPORT_URI = "/maintenance/export";
  84. public static final String PROJECT_IMPORT_URI = "/maintenance/import";
  85. public static final String PROJECT_PARTIAL_EXPORT_URI = "/maintenance/partialmdexport";
  86. public static final String PROJECT_PARTIAL_IMPORT_URI = "/maintenance/partialmdimport";
  87. public static final String REPORT_QUERY = "/query/reports";
  88. public static final String ATTR_QUERY = "/query/attributes";
  89. public static final String EXECUTOR = "/gdc/xtab2/executor3";
  90. public static final String EXPORT_EXECUTOR = "/gdc/exporter/executor";
  91. public static final String INVITATION_URI = "/invitations";
  92. public static final String ETL_MODE_URI = "/etl/mode";
  93. public static final String OBJ_URI = "/obj";
  94. public static final String ROLES_URI = "/roles";
  95. public static final String USERS_URI = "/users";
  96. public static final String ETL_MODE_DLI = "DLI";
  97. public static final String ETL_MODE_VOID = "VOID";
  98. public static final String LINKS_UPLOADS_KEY = "uploads";
  99. public static final String DLI_MANIFEST_FILENAME = "upload_info.json";
  100. public static final String QUERY_PROJECTDASHBOARDS = "projectdashboards";
  101. public static final String QUERY_FOLDERS = "folders";
  102. public static final String QUERY_DATASETS = "datasets";
  103. public static final String QUERY_DIMENSIONS = "dimensions";
  104. public static final String QUERY_PREFIX = "/query/";
  105. protected HttpClient client;
  106. protected NamePasswordConfiguration config;
  107. private JSONObject userLogin = null;
  108. private JSONObject profile;
  109. private static HashMap<String, String> ROLES = new HashMap<String, String>();
  110. private static final Pattern NEWLINE_SEPARATOR_PARSER = Pattern.compile( "\n" );
  111. /* TODO This is fragile and may not work for all projects and/or future versions.
  112. * Use /gdc/projects/{projectId}/roles to retrieve roles for a particular project.
  113. */
  114. static {
  115. ROLES.put("ADMIN", "adminRole");
  116. ROLES.put("EDITOR", "editorRole");
  117. ROLES.put("DASHBOARD ONLY", "dashboardOnlyRole");
  118. ROLES.put("UNVERIFIED ADMIN", "unverifiedAdminRole");
  119. ROLES.put("READONLY", "readOnlyUserRole");
  120. }
  121. /**
  122. * Constructs the GoodData REST API Java wrapper
  123. *
  124. * @param config NamePasswordConfiguration object with the GDC name and password configuration
  125. */
  126. public GdcRESTApiWrapper(NamePasswordConfiguration config) {
  127. this.config = config;
  128. client = new HttpClient();
  129. NetUtil.configureHttpProxy(client);
  130. }
  131. /**
  132. * GDC login - obtain GDC SSToken
  133. *
  134. * @throws HttpMethodException
  135. */
  136. public void login() throws HttpMethodException {
  137. //logout();
  138. l.debug("Logging into GoodData.");
  139. JSONObject loginStructure = getLoginStructure();
  140. PostMethod loginPost = createPostMethod(getServerUrl() + LOGIN_URI);
  141. InputStreamRequestEntity request = new InputStreamRequestEntity(new ByteArrayInputStream(loginStructure.toString().getBytes()));
  142. loginPost.setRequestEntity(request);
  143. try {
  144. String resp = executeMethodOk(loginPost, false); // do not re-login on SC_UNAUTHORIZED
  145. // enabling this prevents the following message:
  146. // WARN org.apache.commons.httpclient.HttpMethodDirector -
  147. // Unable to respond to any of these challenges:
  148. // {gooddata=GoodData realm="GoodData API" cookie=GDCAuthTT}
  149. // appearing always after those:
  150. // DEBUG com.gooddata.integration.rest.GdcRESTApiWrapper -
  151. // Logging into GoodData.
  152. // DEBUG com.gooddata.integration.rest.GdcRESTApiWrapper -
  153. // Successfully logged into GoodData.
  154. setTokenCookie();
  155. l.debug("Successfully logged into GoodData.");
  156. JSONObject rsp = JSONObject.fromObject(resp);
  157. userLogin = rsp.getJSONObject("userLogin");
  158. String profileUri = userLogin.getString("profile");
  159. if (profileUri != null && profileUri.length() > 0) {
  160. GetMethod gm = createGetMethod(getServerUrl() + profileUri);
  161. try {
  162. resp = executeMethodOk(gm);
  163. this.profile = JSONObject.fromObject(resp);
  164. }
  165. finally {
  166. gm.releaseConnection();
  167. }
  168. } else {
  169. l.debug("Empty account profile.");
  170. throw new GdcRestApiException("Empty account profile.");
  171. }
  172. } finally {
  173. loginPost.releaseConnection();
  174. }
  175. }
  176. /**
  177. * Creates a new login JSON structure
  178. *
  179. * @return the login JSON structure
  180. */
  181. private JSONObject getLoginStructure() {
  182. JSONObject credentialsStructure = new JSONObject();
  183. credentialsStructure.put("login", config.getUsername());
  184. credentialsStructure.put("password", config.getPassword());
  185. credentialsStructure.put("remember", 1);
  186. JSONObject loginStructure = new JSONObject();
  187. loginStructure.put("postUserLogin", credentialsStructure);
  188. return loginStructure;
  189. }
  190. /**
  191. * Sets the SS token
  192. *
  193. * @throws HttpMethodException
  194. */
  195. private void setTokenCookie() throws HttpMethodException {
  196. HttpMethod secutityTokenGet = createGetMethod(getServerUrl() + TOKEN_URI);
  197. try {
  198. executeMethodOk(secutityTokenGet);
  199. } finally {
  200. secutityTokenGet.releaseConnection();
  201. }
  202. }
  203. /**
  204. * GDC logout - remove active session, if any exists
  205. *
  206. * @throws HttpMethodException
  207. */
  208. public void logout() throws HttpMethodException {
  209. if (userLogin == null)
  210. return;
  211. l.debug("Logging out.");
  212. DeleteMethod logoutDelete = createDeleteMethod(getServerUrl() + userLogin.getString("state"));
  213. try {
  214. String resp = executeMethodOk(logoutDelete, false); // do not re-login on SC_UNAUTHORIZED
  215. userLogin = null;
  216. profile = null;
  217. l.debug("Successfully logged out.");
  218. } finally {
  219. logoutDelete.releaseConnection();
  220. }
  221. this.client = new HttpClient();
  222. NetUtil.configureHttpProxy( client );
  223. }
  224. /**
  225. * Retrieves the project info by the project's ID
  226. *
  227. * @param id the project id
  228. * @return the GoodDataProjectInfo populated with the project's information
  229. * @throws HttpMethodException
  230. * @throws GdcProjectAccessException
  231. */
  232. public Project getProjectById(String id) throws HttpMethodException, GdcProjectAccessException {
  233. l.debug("Getting project by id=" + id);
  234. HttpMethod req = createGetMethod(getServerUrl() + PROJECTS_URI + "/" + id);
  235. try {
  236. String resp = executeMethodOk(req);
  237. JSONObject parsedResp = JSONObject.fromObject(resp);
  238. if(parsedResp != null && !parsedResp.isEmpty() && !parsedResp.isNullObject()) {
  239. JSONObject project = parsedResp.getJSONObject("project");
  240. if(project != null && !project.isEmpty() && !project.isNullObject()) {
  241. JSONObject meta = project.getJSONObject("meta");
  242. String title = meta.getString("title");
  243. if(title != null && title.length() > 0)
  244. return new Project(MD_URI + "/" + id, id, title);
  245. else
  246. throw new InvalidArgumentException("getProjectById: The project structure doesn't contain the title key.");
  247. }
  248. else {
  249. throw new InvalidArgumentException("getProjectById: The project structure doesn't contain the project key.");
  250. }
  251. } else {
  252. throw new InvalidArgumentException("getProjectById: Invalid response.");
  253. }
  254. } catch (HttpMethodException e) {
  255. l.debug("The project id=" + id + " doesn't exists.");
  256. throw new GdcProjectAccessException("The project id=" + id + " doesn't exists.");
  257. } finally {
  258. req.releaseConnection();
  259. }
  260. }
  261. /**
  262. * Returns the global platform links
  263. *
  264. * @return accessible platform links
  265. * @throws com.gooddata.exception.HttpMethodException
  266. *
  267. */
  268. @SuppressWarnings("unchecked")
  269. private Iterator<JSONObject> getPlatformLinks() throws HttpMethodException {
  270. l.debug("Getting project links.");
  271. HttpMethod req = createGetMethod(getServerUrl() + PLATFORM_URI);
  272. try {
  273. String resp = executeMethodOk(req);
  274. JSONObject parsedResp = JSONObject.fromObject(resp);
  275. JSONObject about = parsedResp.getJSONObject("about");
  276. JSONArray links = about.getJSONArray("links");
  277. l.debug("Got platform links " + links);
  278. return links.iterator();
  279. } finally {
  280. req.releaseConnection();
  281. }
  282. }
  283. /**
  284. *
  285. *
  286. * @return the WebDav URL from the platform configuration
  287. */
  288. public URL getWebDavURL() {
  289. Iterator<JSONObject> links = getPlatformLinks();
  290. while(links.hasNext()) {
  291. JSONObject link = links.next();
  292. if(link != null && !link.isEmpty() && !link.isNullObject()) {
  293. String category = link.getString("category");
  294. if(category != null && category.length() > 0 && category.equalsIgnoreCase(LINKS_UPLOADS_KEY)) {
  295. try {
  296. String uri = link.getString("link");
  297. if(uri != null && uri.length()>0) {
  298. if(uri.startsWith("/")) {
  299. uri = getServerUrl() + uri;
  300. }
  301. return new URL(uri);
  302. }
  303. else {
  304. throw new InvalidArgumentException("No uploads URL configured for the server: "+category);
  305. }
  306. }
  307. catch (MalformedURLException e) {
  308. throw new InvalidArgumentException("Invalid uploads URL configured for the server: "+category);
  309. }
  310. }
  311. }
  312. }
  313. throw new InvalidArgumentException("No uploads platform link configured for the GoodData cluster.");
  314. }
  315. /**
  316. * Returns a list of project's SLIs
  317. *
  318. * @param projectId project's ID
  319. * @return a list of project's SLIs
  320. * @throws HttpMethodException if there is a communication error
  321. * @throws GdcProjectAccessException if the SLI doesn't exist
  322. */
  323. public List<SLI> getSLIs(String projectId) throws HttpMethodException, GdcProjectAccessException {
  324. l.debug("Getting SLIs from project id=" + projectId);
  325. List<SLI> list = new ArrayList<SLI>();
  326. String ifcUri = getSLIsUri(projectId);
  327. HttpMethod interfacesGet = createGetMethod(ifcUri);
  328. try {
  329. String response = executeMethodOk(interfacesGet);
  330. JSONObject responseObject = JSONObject.fromObject(response);
  331. if (responseObject.isNullObject()) {
  332. l.debug("The project id=" + projectId + " doesn't exist!");
  333. throw new GdcProjectAccessException("The project id=" + projectId + " doesn't exist!");
  334. }
  335. JSONObject interfaceQuery = responseObject.getJSONObject("about");
  336. if (interfaceQuery.isNullObject()) {
  337. l.debug("The project id=" + projectId + " doesn't exist!");
  338. throw new GdcProjectAccessException("The project id=" + projectId + " doesn't exist!");
  339. }
  340. JSONArray links = interfaceQuery.getJSONArray("links");
  341. if (links == null) {
  342. l.debug("The project id=" + projectId + " doesn't exist!");
  343. throw new GdcProjectAccessException("The project id=" + projectId + " doesn't exist!");
  344. }
  345. for (Object ol : links) {
  346. JSONObject link = (JSONObject) ol;
  347. SLI ii = new SLI(link);
  348. list.add(ii);
  349. }
  350. l.debug("Got SLIs " + list + " from project id=" + projectId);
  351. } finally {
  352. interfacesGet.releaseConnection();
  353. }
  354. return list;
  355. }
  356. /**
  357. * Retrieves the SLI columns
  358. *
  359. * @param uri the SLI uri
  360. * @return list of SLI columns
  361. * @throws GdcProjectAccessException if the SLI doesn't exist
  362. * @throws HttpMethodException if there is a communication issue with the GDC platform
  363. */
  364. public List<Column> getSLIColumns(String uri) throws GdcProjectAccessException, HttpMethodException {
  365. l.debug("Retrieveing SLI columns for SLI uri=" + uri);
  366. List<Column> list = new ArrayList<Column>();
  367. HttpMethod sliGet = createGetMethod(getServerUrl() + uri + "/manifest");
  368. try {
  369. String response = executeMethodOk(sliGet);
  370. JSONObject responseObject = JSONObject.fromObject(response);
  371. if (responseObject.isNullObject()) {
  372. l.debug("The SLI uri=" + uri + " doesn't exist!");
  373. throw new GdcProjectAccessException("The SLI uri=" + uri + " doesn't exist!");
  374. }
  375. JSONObject dataSetSLIManifest = responseObject.getJSONObject("dataSetSLIManifest");
  376. if (dataSetSLIManifest.isNullObject()) {
  377. l.debug("The SLI uri=" + uri + " doesn't exist!");
  378. throw new GdcProjectAccessException("The SLI uri=" + uri + " doesn't exist!");
  379. }
  380. JSONArray parts = dataSetSLIManifest.getJSONArray("parts");
  381. for (Object oPart : parts) {
  382. list.add(new Column((JSONObject) oPart));
  383. }
  384. } finally {
  385. sliGet.releaseConnection();
  386. }
  387. return list;
  388. }
  389. /**
  390. * Retrieves the SLI column data type
  391. *
  392. * @param projectId projectId
  393. * @param sliColumnIdentifier SLI column identifier (name in the SLI manifest)
  394. * @return the SLI column datatype
  395. */
  396. public String getSLIColumnDataType(String projectId, String sliColumnIdentifier) {
  397. l.debug("Retrieveing SLI column datatype projectId=" + projectId + " SLI column name=" + sliColumnIdentifier);
  398. MetadataObject o = getMetadataObject(projectId, sliColumnIdentifier);
  399. if (o != null) {
  400. JSONObject c = o.getContent();
  401. if (c != null) {
  402. String type = c.getString("columnType");
  403. if (type != null && type.length() > 0) {
  404. return type;
  405. } else {
  406. l.debug("Error Retrieveing SLI column datatype projectId=" + projectId + " SLI column name=" + sliColumnIdentifier + " No columnType key in the content.");
  407. throw new GdcRestApiException("Error Retrieveing SLI column datatype projectId=" + projectId + " SLI column name=" + sliColumnIdentifier + " No columnType key in the content.");
  408. }
  409. } else {
  410. l.debug("Error Retrieveing SLI column datatype projectId=" + projectId + " SLI column name=" + sliColumnIdentifier + " No content structure.");
  411. throw new GdcRestApiException("Error Retrieveing SLI column datatype projectId=" + projectId + " SLI column name=" + sliColumnIdentifier + " No content structure.");
  412. }
  413. } else {
  414. l.debug("Error Retrieveing SLI column datatype projectId=" + projectId + " SLI column name=" + sliColumnIdentifier + " MD object doesn't exist.");
  415. throw new GdcRestApiException("Error Retrieveing SLI column datatype projectId=" + projectId + " SLI column name=" + sliColumnIdentifier + " MD object doesn't exist.");
  416. }
  417. }
  418. /**
  419. * Retrieves the SLI columns
  420. *
  421. * @param uri the SLI uri
  422. * @return JSON manifest
  423. * @throws GdcProjectAccessException if the SLI doesn't exist
  424. * @throws HttpMethodException if there is a communication issue with the GDC platform
  425. */
  426. public JSONObject getSLIManifest(String uri) throws GdcProjectAccessException, HttpMethodException {
  427. l.debug("Retrieveing SLI columns for SLI uri=" + uri);
  428. List<Column> list = new ArrayList<Column>();
  429. HttpMethod sliGet = createGetMethod(getServerUrl() + uri + "/manifest");
  430. try {
  431. String response = executeMethodOk(sliGet);
  432. JSONObject responseObject = JSONObject.fromObject(response);
  433. if (responseObject.isNullObject()) {
  434. l.debug("The SLI uri=" + uri + " doesn't exist!");
  435. throw new GdcProjectAccessException("The SLI uri=" + uri + " doesn't exist!");
  436. }
  437. return responseObject;
  438. } finally {
  439. sliGet.releaseConnection();
  440. }
  441. }
  442. /**
  443. * Finds a project SLI by it's id
  444. *
  445. * @param id the SLI id
  446. * @param projectId the project id
  447. * @return the SLI
  448. * @throws GdcProjectAccessException if the SLI doesn't exist
  449. * @throws HttpMethodException if there is a communication issue with the GDC platform
  450. */
  451. public SLI getSLIById(String id, String projectId) throws GdcProjectAccessException, HttpMethodException {
  452. l.debug("Get SLI by id=" + id + " project id=" + projectId);
  453. List<SLI> slis = getSLIs(projectId);
  454. return getSLIById(id, slis, projectId);
  455. }
  456. /**
  457. * Finds a project SLI in list of SLI
  458. *
  459. * @param id the SLI id
  460. * @param slis of SLI (related to one project)
  461. * @param projectId the project id
  462. * @return the SLI
  463. * @throws GdcProjectAccessException if the SLI doesn't exist
  464. */
  465. public static SLI getSLIById(String id, List<SLI> slis, String projectId) throws GdcProjectAccessException {
  466. l.debug("Get SLI by id=" + id + " project id=" + projectId);
  467. for (SLI sli : slis) {
  468. if (id.equals(sli.getId())) {
  469. l.debug("Got SLI by id=" + id + " project id=" + projectId);
  470. return sli;
  471. }
  472. }
  473. l.debug("The SLI id=" + id + " doesn't exist in the project id=" + projectId);
  474. throw new GdcProjectAccessException("The SLI id=" + id + " doesn't exist in the project id=" + projectId);
  475. }
  476. /**
  477. * Enumerates all attributes in the project
  478. *
  479. * @param projectId project Id
  480. * @return LIst of attr uris
  481. */
  482. public List<String> enumerateAttributes(String projectId) {
  483. l.debug("Enumerating attributes for project id=" + projectId);
  484. List<String> list = new ArrayList<String>();
  485. String qUri = getProjectMdUrl(projectId) + ATTR_QUERY;
  486. HttpMethod qGet = createGetMethod(qUri);
  487. try {
  488. String qr = executeMethodOk(qGet);
  489. JSONObject q = JSONObject.fromObject(qr);
  490. if (q.isNullObject()) {
  491. l.debug("Enumerating attributes for project id=" + projectId + " failed.");
  492. throw new GdcProjectAccessException("Enumerating attributes for project id=" + projectId + " failed.");
  493. }
  494. JSONObject qry = q.getJSONObject("query");
  495. if (qry.isNullObject()) {
  496. l.debug("Enumerating attributes for project id=" + projectId + " failed.");
  497. throw new GdcProjectAccessException("Enumerating reports for project id=" + projectId + " failed.");
  498. }
  499. JSONArray entries = qry.getJSONArray("entries");
  500. if (entries == null) {
  501. l.debug("Enumerating attributes for project id=" + projectId + " failed.");
  502. throw new GdcProjectAccessException("Enumerating reports for project id=" + projectId + " failed.");
  503. }
  504. for (Object oentry : entries) {
  505. JSONObject entry = (JSONObject) oentry;
  506. list.add(entry.getString("link"));
  507. }
  508. } finally {
  509. qGet.releaseConnection();
  510. }
  511. return list;
  512. }
  513. /**
  514. * Gets attribute PK
  515. *
  516. * @param attrUri attribute URI
  517. * @return list of attribute PKs (columns)
  518. */
  519. public List<JSONObject> getAttributePk(String attrUri) {
  520. List<JSONObject> ret = new ArrayList<JSONObject>();
  521. JSONObject attr = getObjectByUri(attrUri);
  522. JSONObject a = attr.getJSONObject("attribute");
  523. if (a != null && !a.isEmpty() && !a.isEmpty()) {
  524. JSONObject c = a.getJSONObject("content");
  525. if (c != null && !c.isEmpty() && !c.isEmpty()) {
  526. JSONArray pks = c.getJSONArray("pk");
  527. if (pks != null && !pks.isEmpty()) {
  528. Object[] p = pks.toArray();
  529. for (Object pko : p) {
  530. JSONObject pk = (JSONObject) pko;
  531. String columnUri = pk.getString("data");
  532. if (columnUri != null) {
  533. ret.add(getObjectByUri(columnUri));
  534. } else {
  535. l.debug("Error getting attribute PK. No PK data.");
  536. throw new GdcProjectAccessException("Error getting attribute PK. No PK data.");
  537. }
  538. }
  539. }
  540. } else {
  541. l.debug("Error getting attribute PK. No content.");
  542. throw new GdcProjectAccessException("Error getting attribute PK. No content.");
  543. }
  544. } else {
  545. l.debug("Error getting attribute PK. No attribute.");
  546. throw new GdcProjectAccessException("Error getting attribute PK. No attribute.");
  547. }
  548. return ret;
  549. }
  550. /**
  551. * Gets attribute FK
  552. *
  553. * @param attrUri attribute URI
  554. * @return list of attribute FKs (columns)
  555. */
  556. public List<JSONObject> getAttributeFk(String attrUri) {
  557. List<JSONObject> ret = new ArrayList<JSONObject>();
  558. JSONObject attr = getObjectByUri(attrUri);
  559. JSONObject a = attr.getJSONObject("attribute");
  560. if (a != null && !a.isEmpty() && !a.isEmpty()) {
  561. JSONObject c = a.getJSONObject("content");
  562. if (c != null && !c.isEmpty() && !c.isEmpty()) {
  563. if (c.containsKey("fk")) {
  564. JSONArray pks = c.getJSONArray("fk");
  565. if (pks != null && !pks.isEmpty()) {
  566. Object[] p = pks.toArray();
  567. for (Object pko : p) {
  568. JSONObject pk = (JSONObject) pko;
  569. String columnUri = pk.getString("data");
  570. if (columnUri != null && columnUri.trim().length() > 0) {
  571. ret.add(getObjectByUri(columnUri));
  572. } else {
  573. l.debug("Error getting attribute FK. No FK data.");
  574. throw new GdcProjectAccessException("Error getting attribute FK. No FK data.");
  575. }
  576. }
  577. }
  578. }
  579. } else {
  580. l.debug("Error getting attribute FK. No content.");
  581. throw new GdcProjectAccessException("Error getting attribute FK. No content.");
  582. }
  583. } else {
  584. l.debug("Error getting attribute FK. No attribute.");
  585. throw new GdcProjectAccessException("Error getting attribute FK. No attribute.");
  586. }
  587. return ret;
  588. }
  589. /**
  590. * Gets column DB name
  591. *
  592. * @param column column object
  593. * @return column DB name
  594. */
  595. public String getColumnDbName(JSONObject column) {
  596. JSONObject cl = column.getJSONObject("column");
  597. if (cl != null && !cl.isEmpty() && !cl.isEmpty()) {
  598. JSONObject c = cl.getJSONObject("content");
  599. if (c != null && !c.isEmpty() && !c.isEmpty()) {
  600. String cn = c.getString("columnDBName");
  601. if (cn != null && cn.trim().length() > 0) {
  602. return cn;
  603. } else {
  604. l.debug("Error getting column name. No columnDBName.");
  605. throw new GdcProjectAccessException("Error getting column name. No columnDBName.");
  606. }
  607. } else {
  608. l.debug("Error getting column name. No content.");
  609. throw new GdcProjectAccessException("Error getting column name. No content.");
  610. }
  611. } else {
  612. l.debug("Error getting column name. No column.");
  613. throw new GdcProjectAccessException("Error getting column name. No column.");
  614. }
  615. }
  616. /**
  617. * Gets column table name
  618. *
  619. * @param column column object
  620. * @return column table name
  621. */
  622. public String getColumnTableName(JSONObject column) {
  623. JSONObject cl = column.getJSONObject("column");
  624. if (cl != null && !cl.isEmpty() && !cl.isEmpty()) {
  625. JSONObject c = cl.getJSONObject("content");
  626. if (c != null && !c.isEmpty() && !c.isEmpty()) {
  627. String t = c.getString("table");
  628. if (t != null && t.trim().length() > 0) {
  629. JSONObject tbl = getObjectByUri(t);
  630. JSONObject root = tbl.getJSONObject("table");
  631. if (root != null && !root.isEmpty() && !root.isEmpty()) {
  632. c = root.getJSONObject("content");
  633. if (c != null && !c.isEmpty() && !c.isEmpty()) {
  634. String dl = c.getString("activeDataLoad");
  635. if (dl != null && dl.trim().length() > 0) {
  636. JSONObject tdl = getObjectByUri(dl);
  637. root = tdl.getJSONObject("tableDataLoad");
  638. if (root != null && !root.isEmpty() && !root.isEmpty()) {
  639. c = root.getJSONObject("content");
  640. if (c != null && !c.isEmpty() && !c.isEmpty()) {
  641. String tn = c.getString("dataSourceLocation");
  642. if (tn != null && tn.trim().length() > 0) {
  643. return tn;
  644. } else {
  645. l.debug("Error getting column name. No dataSourceLocation.");
  646. throw new GdcProjectAccessException("Error getting column name. No dataSourceLocation.");
  647. }
  648. } else {
  649. l.debug("Error getting column name. No active table data load content.");
  650. throw new GdcProjectAccessException("Error getting column name. No active table data load content.");
  651. }
  652. } else {
  653. l.debug("Error getting column name. No table data load root.");
  654. throw new GdcProjectAccessException("Error getting column name. No table data load root.");
  655. }
  656. } else {
  657. l.debug("Error getting column name. No active data load.");
  658. throw new GdcProjectAccessException("Error getting column name. No active data load.");
  659. }
  660. } else {
  661. l.debug("Error getting column name. No table content.");
  662. throw new GdcProjectAccessException("Error getting column name. No table content.");
  663. }
  664. } else {
  665. l.debug("Error getting column table. No table root.");
  666. throw new GdcProjectAccessException("Error getting column table. No table root.");
  667. }
  668. } else {
  669. l.debug("Error getting column name. No table.");
  670. throw new GdcProjectAccessException("Error getting column name. No table.");
  671. }
  672. } else {
  673. l.debug("Error getting column name. No content.");
  674. throw new GdcProjectAccessException("Error getting column name. No content.");
  675. }
  676. } else {
  677. l.debug("Error getting column name. No column.");
  678. throw new GdcProjectAccessException("Error getting column name. No column.");
  679. }
  680. }
  681. /**
  682. * Enumerates all attributes in the project
  683. *
  684. * @param attrUri attribute URI
  685. * @return attribute object
  686. */
  687. public JSONObject getAttribute(String attrUri) {
  688. l.debug("Getting attribute uri=" + attrUri);
  689. String qUri = getServerUrl() + attrUri;
  690. HttpMethod qGet = createGetMethod(qUri);
  691. try {
  692. String qr = executeMethodOk(qGet);
  693. return JSONObject.fromObject(qr);
  694. } finally {
  695. qGet.releaseConnection();
  696. }
  697. }
  698. /**
  699. * Enumerates all reports on in a project
  700. *
  701. * @param projectId project Id
  702. * @return LIst of report uris
  703. */
  704. public List<String> enumerateReports(String projectId) {
  705. l.debug("Enumerating reports for project id=" + projectId);
  706. List<String> list = new ArrayList<String>();
  707. String qUri = getProjectMdUrl(projectId) + REPORT_QUERY;
  708. HttpMethod qGet = createGetMethod(qUri);
  709. try {
  710. String qr = executeMethodOk(qGet);
  711. JSONObject q = JSONObject.fromObject(qr);
  712. if (q.isNullObject()) {
  713. l.debug("Enumerating reports for project id=" + projectId + " failed.");
  714. throw new GdcProjectAccessException("Enumerating reports for project id=" + projectId + " failed.");
  715. }
  716. JSONObject qry = q.getJSONObject("query");
  717. if (qry.isNullObject()) {
  718. l.debug("Enumerating reports for project id=" + projectId + " failed.");
  719. throw new GdcProjectAccessException("Enumerating reports for project id=" + projectId + " failed.");
  720. }
  721. JSONArray entries = qry.getJSONArray("entries");
  722. if (entries == null) {
  723. l.debug("Enumerating reports for project id=" + projectId + " failed.");
  724. throw new GdcProjectAccessException("Enumerating reports for project id=" + projectId + " failed.");
  725. }
  726. for (Object oentry : entries) {
  727. JSONObject entry = (JSONObject) oentry;
  728. int deprecated = entry.getInt("deprecated");
  729. if (deprecated == 0)
  730. list.add(entry.getString("link"));
  731. }
  732. } finally {
  733. qGet.releaseConnection();
  734. }
  735. return list;
  736. }
  737. private String getProjectIdFromObjectUri(String uri) {
  738. Pattern regexp = Pattern.compile("gdc/md/.*?/");
  739. Matcher m = regexp.matcher(uri);
  740. if (m.find()) {
  741. return m.group().split("/")[2];
  742. } else {
  743. l.debug("The passed string '" + uri + "' doesn't have the GoodData URI structure!");
  744. throw new InvalidParameterException("The passed string '" + uri + "' doesn't have the GoodData URI structure!");
  745. }
  746. }
  747. /**
  748. * Computes the metric value
  749. *
  750. * @param metricUri metric URI
  751. * @return the metric value
  752. */
  753. public double computeMetric(String metricUri) {
  754. l.debug("Computing metric uri=" + metricUri);
  755. double retVal = 0;
  756. String projectId = getProjectIdFromObjectUri(metricUri);
  757. JSONObject reportDefinition = new JSONObject();
  758. JSONObject metric = new JSONObject();
  759. metric.put("alias", "");
  760. metric.put("uri", metricUri);
  761. JSONArray metrics = new JSONArray();
  762. metrics.add(metric);
  763. JSONArray columns = new JSONArray();
  764. columns.add("metricGroup");
  765. JSONObject grid = new JSONObject();
  766. grid.put("metrics", metrics);
  767. grid.put("columns", columns);
  768. grid.put("rows", new JSONArray());
  769. grid.put("columnWidths", new JSONArray());
  770. JSONObject sort = new JSONObject();
  771. sort.put("columns", new JSONArray());
  772. sort.put("rows", new JSONArray());
  773. grid.put("sort", sort);
  774. JSONObject content = new JSONObject();
  775. content.put("grid", grid);
  776. content.put("filters", new JSONArray());
  777. content.put("format", "grid");
  778. reportDefinition.put("content", content);
  779. JSONObject meta = new JSONObject();
  780. meta.put("category", "reportDefinition");
  781. meta.put("title", "N/A");
  782. reportDefinition.put("meta", meta);
  783. MetadataObject obj = new MetadataObject();
  784. obj.put("reportDefinition", reportDefinition);
  785. MetadataObject resp = new MetadataObject(createMetadataObject(projectId, obj));
  786. int retryCnt = Constants.MAX_RETRY;
  787. boolean hasFinished = false;
  788. while (retryCnt-- > 0 && !hasFinished) {
  789. try {
  790. String dataResultUri = executeReportDefinition(resp.getUri());
  791. JSONObject result = getObjectByUri(dataResultUri);
  792. hasFinished = true;
  793. if (result != null && !result.isEmpty() && !result.isNullObject()) {
  794. JSONObject xtabData = result.getJSONObject("xtab_data");
  795. if (xtabData != null && !xtabData.isEmpty() && !xtabData.isNullObject()) {
  796. JSONArray data = xtabData.getJSONArray("data");
  797. if (data != null && !data.isEmpty()) {
  798. retVal = data.getJSONArray(0).getDouble(0);
  799. } else {
  800. l.debug("Can't compute the metric. No data structure in result.");
  801. throw new InvalidParameterException("Can't compute the metric. No data structure in result.");
  802. }
  803. } else {
  804. l.debug("Can't compute the metric. No xtab_data structure in result.");
  805. throw new InvalidParameterException("Can't compute the metric. No xtab_data structure in result.");
  806. }
  807. } else {
  808. l.debug("Can't compute the metric. No result from XTAB.");
  809. throw new InvalidParameterException("Can't compute the metric. No result from XTAB.");
  810. }
  811. } catch (HttpMethodNotFinishedYetException e) {
  812. l.debug("computeMetric: Waiting for DataResult");
  813. try {
  814. Thread.sleep(Constants.POLL_INTERVAL);
  815. } catch (InterruptedException ex) {
  816. // do nothing
  817. }
  818. }
  819. }
  820. l.debug("Metric uri=" + metricUri + " computed. Result is " + retVal);
  821. return retVal;
  822. }
  823. /**
  824. * Computes a simple report and returns the report text
  825. *
  826. * @param reportUri report URI
  827. * @return the report rendered in text
  828. */
  829. public String computeReport(String reportUri) {
  830. l.debug("Computing report uri=" + reportUri);
  831. String retVal = "";
  832. int retryCnt = Constants.MAX_RETRY;
  833. boolean hasFinished = false;
  834. while (retryCnt-- > 0 && !hasFinished) {
  835. try {
  836. String dataResultUri = executeReport(reportUri);
  837. JSONObject result = getObjectByUri(dataResultUri);
  838. hasFinished = true;
  839. if (result != null && !result.isEmpty() && !result.isNullObject()) {
  840. JSONObject xtabData = result.getJSONObject("xtab_data");
  841. if (xtabData != null && !xtabData.isEmpty() && !xtabData.isNullObject()) {
  842. JSONArray data = xtabData.getJSONArray("data");
  843. if (data != null && !data.isEmpty()) {
  844. double[] values = new double[data.size()];
  845. for (int i = 0; i < data.size(); i++) {
  846. JSONArray vals = data.getJSONArray(i);
  847. values[i] = vals.getDouble(0);
  848. }
  849. JSONObject rows = xtabData.getJSONObject("rows");
  850. if (rows != null && !rows.isEmpty() && !rows.isNullObject()) {
  851. JSONArray lookups = rows.getJSONArray("lookups");
  852. if (lookups != null && !lookups.isEmpty()) {
  853. Map<String, String> attributes = new HashMap<String, String>();
  854. JSONObject lkpData = lookups.getJSONObject(0);
  855. for (Object key : lkpData.keySet()) {
  856. Object value = lkpData.get(key);
  857. if (key != null && value != null)
  858. attributes.put(key.toString(), value.toString());
  859. }
  860. JSONObject tree = rows.getJSONObject("tree");
  861. if (tree != null && !tree.isEmpty() && !tree.isNullObject()) {
  862. Map<String, Integer> indexes = new HashMap<String, Integer>();
  863. JSONObject index = tree.getJSONObject("index");
  864. if (index != null && !index.isEmpty()) {
  865. for (Object key : index.keySet()) {
  866. if (key != null) {
  867. JSONArray valIdxs = index.getJSONArray(key.toString());
  868. if (valIdxs != null && !valIdxs.isEmpty()) {
  869. indexes.put(key.toString(), valIdxs.getInt(0));
  870. }
  871. }
  872. }
  873. JSONArray children = tree.getJSONArray("children");
  874. if (children != null && !children.isEmpty()) {
  875. for (int i = 0; i < children.size(); i++) {
  876. JSONObject c = children.getJSONObject(i);
  877. String id = c.getString("id");
  878. if (id != null && id.length() > 0) {
  879. String attribute = attributes.get(id);
  880. int v = indexes.get(id);
  881. double vl = values[v];
  882. if (retVal.length() > 0) {
  883. retVal += ", " + attribute + " : " + vl;
  884. } else {
  885. retVal += attribute + " : " + vl;
  886. }
  887. } else {
  888. l.debug("Can't compute the report. No id in children.");
  889. throw new InvalidParameterException("Can't compute the report. No id in children.");
  890. }
  891. }
  892. } else {
  893. l.debug("Can't compute the report. No tree structure in result.");
  894. throw new InvalidParameterException("Can't compute the report. No tree structure in result.");
  895. }
  896. } else {
  897. l.debug("Can't compute the report. No index structure in result.");
  898. throw new InvalidParameterException("Can't compute the report. No index structure in result.");
  899. }
  900. } else {
  901. l.debug("Can't compute the report. No tree structure in result.");
  902. throw new InvalidParameterException("Can't compute the report. No tree structure in result.");
  903. }
  904. } else {
  905. l.debug("Can't compute the report. No lookups structure in result.");
  906. throw new InvalidParameterException("Can't compute the report. No lookups structure in result.");
  907. }
  908. } else {
  909. l.debug("Can't compute the report. No rows structure in result.");
  910. throw new InvalidParameterException("Can't compute the report. No rows structure in result.");
  911. }
  912. } else {
  913. l.debug("Can't compute the report. No data structure in result.");
  914. throw new InvalidParameterException("Can't compute the report. No data structure in result.");
  915. }
  916. } else {
  917. l.debug("Can't compute the report. No xtab_data structure in result.");
  918. throw new InvalidParameterException("Can't compute the report. No xtab_data structure in result.");
  919. }
  920. } else {
  921. l.debug("Can't compute the report. No result from XTAB.");
  922. throw new InvalidParameterException("Can't compute the metric. No result from XTAB.");
  923. }
  924. } catch (HttpMethodNotFinishedYetException e) {
  925. l.debug("computeReport: Waiting for DataResult");
  926. try {
  927. Thread.sleep(Constants.POLL_INTERVAL);
  928. } catch (InterruptedException ex) {
  929. // do nothing
  930. }
  931. }
  932. }
  933. l.debug("Report uri=" + reportUri + " computed.");
  934. return retVal;
  935. }
  936. /**
  937. * Report definition to execute
  938. *
  939. * @param reportDefUri report definition to execute
  940. */
  941. public String executeReportDefinition(String reportDefUri) {
  942. l.debug("Executing report definition uri=" + reportDefUri);
  943. PostMethod execPost = createPostMethod(getServerUrl() + EXECUTOR);
  944. JSONObject execDef = new JSONObject();
  945. execDef.put("reportDefinition", reportDefUri);
  946. JSONObject exec = new JSONObject();
  947. exec.put("report_req", execDef);
  948. InputStreamRequestEntity request = new InputStreamRequestEntity(new ByteArrayInputStream(exec.toString().getBytes()));
  949. execPost.setRequestEntity(request);
  950. try {
  951. String task = executeMethodOk(execPost);
  952. if (task != null && task.length() > 0) {
  953. JSONObject tr = JSONObject.fromObject(task);
  954. if (tr.isNullObject()) {
  955. l.debug("Executing report definition uri=" + reportDefUri + " failed. Returned invalid result result=" + tr);
  956. throw new GdcRestApiException("Executing report definition uri=" + reportDefUri + " failed. " +
  957. "Returned invalid result result=" + tr);
  958. }
  959. JSONObject reportResult = tr.getJSONObject("execResult");
  960. if (reportResult.isNullObject()) {
  961. l.debug("Executing report definition uri=" + reportDefUri + " failed. Returned invalid result result=" + tr);
  962. throw new GdcRestApiException("Executing report definition uri=" + reportDefUri + " failed. " +
  963. "Returned invalid result result=" + tr);
  964. }
  965. String dataResult = reportResult.getString("dataResult");
  966. if (dataResult == null || dataResult.length()<=0) {
  967. l.debug("Executing report definition uri=" + reportDefUri + " failed. Returned invalid result result=" + tr);
  968. throw new GdcRestApiException("Executing report definition uri=" + reportDefUri + " failed. " +
  969. "Returned invalid result result=" + tr);
  970. }
  971. return dataResult;
  972. } else {
  973. l.debug("Executing report definition uri=" + reportDefUri + " failed. Returned invalid task link uri=" + task);
  974. throw new GdcRestApiException("Executing report definition uri=" + reportDefUri +
  975. " failed. Returned invalid task link uri=" + task);
  976. }
  977. } catch (HttpMethodException ex) {
  978. l.debug("Executing report definition uri=" + reportDefUri + " failed.", ex);
  979. throw new GdcRestApiException("Executing report definition uri=" + reportDefUri + " failed.");
  980. } finally {
  981. execPost.releaseConnection();
  982. }

Large files files are truncated, but you can click here to view the full file