diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c9b76619 --- /dev/null +++ b/.gitignore @@ -0,0 +1,56 @@ +# Created by .gitignore support plugin (hsz.mobi) +### Android template +# Built application files +*.apk +*.ap_ + +# Files for the Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm + +## Directory-based project format +.idea/ + +## File-based project format +*.ipr +*.iml +*.iws + +## Additional for IntelliJ +out/ + +# generated by mpeltonen/sbt-idea plugin +.idea_modules/ + +# generated by JIRA plugin +atlassian-ide-plugin.xml + +# generated by Crashlytics plugin (for Android Studio and Intellij) +com_crashlytics_export_strings.xml.DS_Store +.idea* +*.iml +*.db +out +bin +gen diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..b1f1bf29 --- /dev/null +++ b/build.gradle @@ -0,0 +1,41 @@ +buildscript { + repositories { + jcenter() + mavenCentral() + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + mavenLocal() + } + dependencies { + classpath "com.android.tools.build:gradle:0.14.2" + classpath "com.github.dcendents:android-maven-plugin:1.2" + } +} + +subprojects { + group = 'com.jaspersoft.android.sdk' + version = '1.9' + + ext.androidMinSdkVersion = 9 + ext.androidTargetSdkVersion = 19 + ext.androidCompileSdkVersion = 19 + ext.androidBuildToolsVersion = "19.1" + + repositories { + jcenter() + mavenCentral() + mavenLocal() + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + maven { url "file://${System.getenv("ANDROID_HOME")}/extras/android/m2repository" } + } +} + +apply plugin: 'java' // ensure clean is also triggered for root build folder +apply plugin: 'build-dashboard' + +buildDashboard { + reports.html.destination = "build/" +} + +test.reports.html.enabled = false // just clean up dashboard from not generated reports +test.reports.junitXml.enabled = false // just clean up dashboard from not generated reports + diff --git a/client/build.gradle b/client/build.gradle new file mode 100644 index 00000000..e0fe023f --- /dev/null +++ b/client/build.gradle @@ -0,0 +1,51 @@ +apply plugin: 'com.android.library' +apply plugin: 'android-maven' + +description = 'js-android-sdk-client' + +ext { + PUBLISH_GROUP_ID = group + PUBLISH_ARTIFACT_ID = description + PUBLISH_VERSION = '1.9' +} + +android { + compileSdkVersion androidCompileSdkVersion + buildToolsVersion androidBuildToolsVersion + + defaultConfig { + minSdkVersion androidMinSdkVersion + targetSdkVersion androidTargetSdkVersion + versionCode 9010900 + versionName version + } + + packagingOptions { + exclude 'META-INF/notice.txt' + exclude 'META-INF/license.txt' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } + lintOptions { + abortOnError false + } + + buildTypes { + debug { + runProguard false + } + } +} + +dependencies { + compile 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE' + compile 'com.octo.android.robospice:robospice:1.4.14' + compile 'com.octo.android.robospice:robospice-spring-android:1.4.14' + compile('org.simpleframework:simple-xml:2.7') { + exclude group: 'stax', module: 'stax' + exclude group: 'stax', module: 'stax-api' + exclude group: 'xpp3', module: 'xpp3' + } +} + +apply from: '../scripts/android-release-aar.gradle' \ No newline at end of file diff --git a/client/pom.xml b/client/pom.xml deleted file mode 100644 index 9d044551..00000000 --- a/client/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - 4.0.0 - - - js-android-sdk-aggregator - com.jaspersoft.android.sdk - 1.8 - - - js-android-sdk-client - js-android-sdk-client - 1.8 - - - - - com.google.android - android - - - org.springframework.android - spring-android-rest-template - - - com.octo.android.robospice - robospice - - - com.octo.android.robospice - robospice-spring-android - - - - org.simpleframework - simple-xml - - - - stax - stax - - - stax-api - stax - - - - xpp3 - xpp3 - - - - - - junit - junit - - - org.mockito - mockito-all - - - - - - - - org.apache.maven.plugins - maven-source-plugin - - - - - \ No newline at end of file diff --git a/client/src/androidTest/AndroidManifest.xml b/client/src/androidTest/AndroidManifest.xml new file mode 100644 index 00000000..9813f103 --- /dev/null +++ b/client/src/androidTest/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/CheckReportStatusRequestTest.java b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/CheckReportStatusRequestTest.java new file mode 100644 index 00000000..f09fdaf3 --- /dev/null +++ b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/CheckReportStatusRequestTest.java @@ -0,0 +1,35 @@ +package com.jaspersoft.android.sdk.integration; + +import com.jaspersoft.android.sdk.client.async.request.CheckReportStatusRequest; +import com.jaspersoft.android.sdk.client.async.request.RunReportExecutionRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionResponse; +import com.jaspersoft.android.sdk.client.oxm.report.ReportStatusResponse; +import com.jaspersoft.android.sdk.integration.utils.ProtoInstrumentation; +import com.jaspersoft.android.sdk.integration.utils.SampleData; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class CheckReportStatusRequestTest extends ProtoInstrumentation { + + private RunReportExecutionRequest runReportExecutionRequest; + + @Override + protected void setUp() throws Exception { + super.setUp(); + ReportExecutionRequest reportExecutionRequest = SampleData.getSampleExecutionData(getJsRestClient(), RESOURCE_URI); + runReportExecutionRequest = new RunReportExecutionRequest(getJsRestClient(), reportExecutionRequest); + } + + public void test_requestReportStatus() throws Exception { + ReportExecutionResponse runReportExecutionResponse = runReportExecutionRequest.loadDataFromNetwork(); + String requestId = runReportExecutionResponse.getRequestId(); + + CheckReportStatusRequest checkReportStatusRequest = new CheckReportStatusRequest(getJsRestClient(), requestId); + ReportStatusResponse response = checkReportStatusRequest.loadDataFromNetwork(); + assertFalse(response.getStatus() == null); + } + +} diff --git a/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/GetRootFolderDataRequestTest.java b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/GetRootFolderDataRequestTest.java new file mode 100644 index 00000000..adb90921 --- /dev/null +++ b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/GetRootFolderDataRequestTest.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.jaspersoft.android.sdk.integration; + +import com.jaspersoft.android.sdk.client.async.request.GetRootFolderDataRequest; +import com.jaspersoft.android.sdk.client.oxm.report.FolderDataResponse; +import com.jaspersoft.android.sdk.integration.utils.ProtoInstrumentation; + +public class GetRootFolderDataRequestTest extends ProtoInstrumentation { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + public void test_getRootFolderUriMethod() throws Exception { + GetRootFolderDataRequest request = new GetRootFolderDataRequest(getJsRestClient()); + FolderDataResponse response = request.loadDataFromNetwork(); + assertTrue(response.getUri().equals("/")); + } +} diff --git a/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/ReportDetailsRequestTest.java b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/ReportDetailsRequestTest.java new file mode 100644 index 00000000..67b35f5d --- /dev/null +++ b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/ReportDetailsRequestTest.java @@ -0,0 +1,34 @@ +package com.jaspersoft.android.sdk.integration; + +import com.jaspersoft.android.sdk.client.async.request.ReportDetailsRequest; +import com.jaspersoft.android.sdk.client.async.request.RunReportExecutionRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionResponse; +import com.jaspersoft.android.sdk.integration.utils.ProtoInstrumentation; +import com.jaspersoft.android.sdk.integration.utils.SampleData; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class ReportDetailsRequestTest extends ProtoInstrumentation { + + private RunReportExecutionRequest runReportExecutionRequest; + + @Override + protected void setUp() throws Exception { + super.setUp(); + ReportExecutionRequest reportExecutionRequest = SampleData.getSampleExecutionData(getJsRestClient(), RESOURCE_URI); + runReportExecutionRequest = new RunReportExecutionRequest(getJsRestClient(), reportExecutionRequest); + } + + public void test_requestReportDetails() throws Exception { + ReportExecutionResponse runReportExecutionResponse = runReportExecutionRequest.loadDataFromNetwork(); + String requestId = runReportExecutionResponse.getRequestId(); + + ReportDetailsRequest reportDetailsRequest = new ReportDetailsRequest(getJsRestClient(), requestId); + ReportExecutionResponse response = reportDetailsRequest.loadDataFromNetwork(); + assertFalse(response == null); + } + +} diff --git a/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/RunReportExportsRequestTest.java b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/RunReportExportsRequestTest.java new file mode 100644 index 00000000..36008b71 --- /dev/null +++ b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/RunReportExportsRequestTest.java @@ -0,0 +1,54 @@ +package com.jaspersoft.android.sdk.integration; + +import android.test.suitebuilder.annotation.LargeTest; + +import com.jaspersoft.android.sdk.client.async.request.RunReportExecutionRequest; +import com.jaspersoft.android.sdk.client.async.request.RunReportExportOutputRequest; +import com.jaspersoft.android.sdk.client.async.request.RunReportExportsRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ExportExecution; +import com.jaspersoft.android.sdk.client.oxm.report.ExportsRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ReportDataResponse; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionResponse; +import com.jaspersoft.android.sdk.integration.utils.ProtoInstrumentation; +import com.jaspersoft.android.sdk.integration.utils.SampleData; + +/** + * @author Tom Koptel + * @since 1.9 + */ +@LargeTest +public class RunReportExportsRequestTest extends ProtoInstrumentation { + + private RunReportExecutionRequest runReportExecutionRequest; + + @Override + protected void setUp() throws Exception { + super.setUp(); + ReportExecutionRequest reportExecutionRequest = SampleData.getSampleExecutionData(getJsRestClient(), RESOURCE_URI); + runReportExecutionRequest = new RunReportExecutionRequest(getJsRestClient(), reportExecutionRequest); + } + + public void test_requestForExportsOnReport() throws Exception { + ReportExecutionResponse runReportExecutionResponse = runReportExecutionRequest.loadDataFromNetwork(); + String requestId = runReportExecutionResponse.getRequestId(); + + ExportsRequest exr = new ExportsRequest(); +// exr.configureExecutionForProfile(getJsRestClient()); + exr.setMarkupType(ReportExecutionRequest.MARKUP_TYPE_EMBEDDABLE); + exr.setAllowInlineScripts(false); + exr.setOutputFormat("html"); + exr.setPages("1"); + + RunReportExportsRequest runReportExportsRequest = new RunReportExportsRequest(getJsRestClient(), exr, requestId); + ExportExecution runReportExportsResponse = runReportExportsRequest.loadDataFromNetwork(); + assertFalse(runReportExportsResponse == null); + + String executionId = runReportExportsResponse.getId(); + RunReportExportOutputRequest runReportExportOutputRequest + = new RunReportExportOutputRequest(getJsRestClient(), requestId, executionId); + ReportDataResponse response = runReportExportOutputRequest.loadDataFromNetwork(); + assertFalse(response == null); + } + +} diff --git a/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/utils/ProtoInstrumentation.java b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/utils/ProtoInstrumentation.java new file mode 100644 index 00000000..53b5ec98 --- /dev/null +++ b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/utils/ProtoInstrumentation.java @@ -0,0 +1,54 @@ +package com.jaspersoft.android.sdk.integration.utils; + +import android.test.InstrumentationTestCase; + +import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.JsServerProfile; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public abstract class ProtoInstrumentation extends InstrumentationTestCase { + + private static final String DEFAULT_ALIAS = "Mobile Demo"; + private static final String DEFAULT_ORGANIZATION = "organization_1"; + private static final String DEFAULT_SERVER_URL = "http://mobiledemo.jaspersoft.com/jasperserver-pro"; + private static final String DEFAULT_USERNAME = "phoneuser"; + private static final String DEFAULT_PASS = "phoneuser"; + + public static final String RESOURCE_URI = "/Reports/1._Geographic_Results_by_Segment_Report"; + + private JsServerProfile testProfile; + private JsRestClient jsRestClient; + + @Override + protected void setUp() throws Exception { + super.setUp(); + testProfile = new JsServerProfile(); + testProfile.setAlias(DEFAULT_ALIAS); + testProfile.setServerUrl(DEFAULT_SERVER_URL); + testProfile.setOrganization(DEFAULT_ORGANIZATION); + testProfile.setUsername(DEFAULT_USERNAME); + testProfile.setPassword(DEFAULT_PASS); + + jsRestClient = new JsRestClient(); + jsRestClient.setServerProfile(testProfile); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + testProfile = null; + jsRestClient = null; + } + + public JsServerProfile getTestProfile() { + return testProfile; + } + + public JsRestClient getJsRestClient() { + return jsRestClient; + } + +} diff --git a/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/utils/SampleData.java b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/utils/SampleData.java new file mode 100644 index 00000000..1e89244c --- /dev/null +++ b/client/src/androidTest/java/com/jaspersoft/android/sdk/integration/utils/SampleData.java @@ -0,0 +1,39 @@ +package com.jaspersoft.android.sdk.integration.utils; + +import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.JsServerProfile; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionRequest; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class SampleData { + private static final String ATTACHMENT_PREFIX_5_6 = "/reportExecutions/{reportExecutionId}/exports/{exportExecutionId}/attachments/"; + private static final String ATTACHMENT_PREFIX_5_0 = "/reportExecutions/{reportExecutionId}/exports/{exportOptions}/attachments/"; + + private SampleData() {} + + public static ReportExecutionRequest getSampleExecutionData(JsRestClient jsRestClient, String resourceUri) { + ReportExecutionRequest reportExecutionRequest = new ReportExecutionRequest(); + + String prefix = ATTACHMENT_PREFIX_5_6; + JsServerProfile jsServerProfile = jsRestClient.getServerProfile(); + String serverUrl = jsServerProfile.getServerUrl(); + String attachmentsPrefix = (jsServerProfile.getServerUrl() + JsRestClient.REST_SERVICES_V2_URI + prefix); + reportExecutionRequest.setAttachmentsPrefix(attachmentsPrefix); + reportExecutionRequest.setBaseUrl(serverUrl); + + reportExecutionRequest.setReportUnitUri(resourceUri); + reportExecutionRequest.setMarkupType(ReportExecutionRequest.MARKUP_TYPE_EMBEDDABLE); + reportExecutionRequest.setOutputFormat("HTML"); + reportExecutionRequest.setPages("1"); + reportExecutionRequest.setAsync(true); + reportExecutionRequest.setInteractive(true); + reportExecutionRequest.setFreshData(false); + reportExecutionRequest.setSaveDataSnapshot(false); + reportExecutionRequest.setAllowInlineScripts(false); + return reportExecutionRequest; + } + +} diff --git a/client/src/main/AndroidManifest.xml b/client/src/main/AndroidManifest.xml new file mode 100644 index 00000000..e5494232 --- /dev/null +++ b/client/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/JsRestClient.java b/client/src/main/java/com/jaspersoft/android/sdk/client/JsRestClient.java index 49dcb672..fe448789 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/JsRestClient.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/JsRestClient.java @@ -24,21 +24,49 @@ package com.jaspersoft.android.sdk.client; -import android.util.Base64; -import com.jaspersoft.android.sdk.client.oxm.*; +import com.jaspersoft.android.sdk.client.oxm.ReportDescriptor; +import com.jaspersoft.android.sdk.client.oxm.ResourceDescriptor; +import com.jaspersoft.android.sdk.client.oxm.ResourceParameter; +import com.jaspersoft.android.sdk.client.oxm.ResourceProperty; +import com.jaspersoft.android.sdk.client.oxm.ResourcesList; import com.jaspersoft.android.sdk.client.oxm.control.InputControl; import com.jaspersoft.android.sdk.client.oxm.control.InputControlState; import com.jaspersoft.android.sdk.client.oxm.control.InputControlStatesList; import com.jaspersoft.android.sdk.client.oxm.control.InputControlsList; -import com.jaspersoft.android.sdk.client.oxm.report.*; +import com.jaspersoft.android.sdk.client.oxm.report.ExportExecution; +import com.jaspersoft.android.sdk.client.oxm.report.ExportsRequest; +import com.jaspersoft.android.sdk.client.oxm.report.FolderDataResponse; +import com.jaspersoft.android.sdk.client.oxm.report.ReportDataResponse; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionRequest; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionResponse; +import com.jaspersoft.android.sdk.client.oxm.report.ReportParameter; +import com.jaspersoft.android.sdk.client.oxm.report.ReportParametersList; +import com.jaspersoft.android.sdk.client.oxm.report.ReportStatusResponse; +import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookupSearchCriteria; import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookupsList; import com.jaspersoft.android.sdk.client.oxm.server.ServerInfo; -import org.springframework.http.*; +import com.jaspersoft.android.sdk.util.CookieHttpRequestInterceptor; +import com.jaspersoft.android.sdk.util.KeepAliveHttpRequestInterceptor; +import com.jaspersoft.android.sdk.util.LocalesHttpRequestInterceptor; +import com.jaspersoft.android.sdk.util.StaticCacheHelper; + +import org.simpleframework.xml.Serializer; +import org.simpleframework.xml.convert.AnnotationStrategy; +import org.simpleframework.xml.core.Persister; +import org.simpleframework.xml.strategy.Strategy; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.http.client.ClientHttpRequest; -import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.xml.SimpleXmlHttpMessageConverter; import org.springframework.util.FileCopyUtils; import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.ResourceAccessException; @@ -50,7 +78,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -75,21 +105,44 @@ public class JsRestClient { public static final String REST_INPUT_CONTROLS_URI = "/inputControls"; public static final String REST_VALUES_URI = "/values"; public static final String REST_SERVER_INFO_URI = "/serverInfo"; - public static final String REST_REPORT_EXECUTIONS= "/reportExecutions"; + public static final String REST_REPORT_EXECUTIONS = "/reportExecutions"; + public static final String REST_REPORT_EXPORTS = "/exports"; + public static final String REST_REPORT_STATUS = "/status"; + public static final String REST_THUMBNAILS = "/thumbnails"; + + private SimpleXmlHttpMessageConverter simpleXmlHttpMessageConverter; // the timeout in milliseconds until a connection is established private int connectTimeout = 15 * 1000; // the socket timeout in milliseconds for waiting for data private int readTimeout = 120 * 1000; - private RestTemplate restTemplate; private JsServerProfile jsServerProfile; private String restServicesUrl; private ServerInfo serverInfo; + private final RestTemplate restTemplate; + private final SimpleClientHttpRequestFactory requestFactory; + + //--------------------------------------------------------------------- + // Constructors + //--------------------------------------------------------------------- public JsRestClient() { - this.restTemplate = new RestTemplate(true); + this(new RestTemplate(true), new SimpleClientHttpRequestFactory()); + } + + public JsRestClient(RestTemplate restTemplate) { + this(restTemplate, new SimpleClientHttpRequestFactory()); + } + + public JsRestClient(RestTemplate restTemplate, + SimpleClientHttpRequestFactory factory) { + this.restTemplate = restTemplate; + this.requestFactory = factory; + + fetchXmlConverter(); + configureAnnotationStrategy(); } //--------------------------------------------------------------------- @@ -100,7 +153,6 @@ public JsRestClient() { * Set the underlying URLConnection's connect timeout. A timeout value of 0 specifies an infinite timeout. * * @param timeout the timeout value in milliseconds - * * @since 1.5 */ public void setConnectTimeout(int timeout) { @@ -110,8 +162,8 @@ public void setConnectTimeout(int timeout) { /** * Set the underlying URLConnection's read timeout. A timeout value of 0 specifies an infinite timeout. - * @param timeout the timeout value in milliseconds * + * @param timeout the timeout value in milliseconds * @since 1.5 */ public void setReadTimeout(int timeout) { @@ -130,22 +182,20 @@ public JsServerProfile getServerProfile() { public void setServerProfile(final JsServerProfile serverProfile) { this.serverInfo = null; this.jsServerProfile = serverProfile; - this.restServicesUrl = serverProfile.getServerUrl() + REST_SERVICES_URI; - - ClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory() { - @Override - protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { - super.prepareConnection(connection, httpMethod); - // Basic Authentication - String authorisation = serverProfile.getUsernameWithOrgId() + ":" + serverProfile.getPassword(); - byte[] encodedAuthorisation = Base64.encode(authorisation.getBytes(), Base64.NO_WRAP); - connection.setRequestProperty("Authorization", "Basic " + new String(encodedAuthorisation)); - // disable buggy keep-alive - connection.setRequestProperty("Connection", "close"); - } - }; - restTemplate.setRequestFactory(factory); - updateRequestFactoryTimeouts(); + + // We allow user to set profile to null value + if (jsServerProfile != null) { + this.restServicesUrl = serverProfile.getServerUrl() + REST_SERVICES_URI; + + updateRequestFactoryTimeouts(); + restTemplate.setRequestFactory(requestFactory); + + List interceptors = new ArrayList(); + interceptors.add(new LocalesHttpRequestInterceptor()); + interceptors.add(new CookieHttpRequestInterceptor(jsServerProfile)); + interceptors.add(new KeepAliveHttpRequestInterceptor()); + restTemplate.setInterceptors(interceptors); + } } /** @@ -153,7 +203,6 @@ protected void prepareConnection(HttpURLConnection connection, String httpMethod * * @return the ServerInfo value * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.4 */ public ServerInfo getServerInfo() throws RestClientException { @@ -166,11 +215,10 @@ public ServerInfo getServerInfo() throws RestClientException { * @param forceUpdate set to true to force update of the server info * @return the ServerInfo value * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.4 */ public ServerInfo getServerInfo(boolean forceUpdate) throws RestClientException { - if(forceUpdate || serverInfo == null) { + if (forceUpdate || serverInfo == null) { String uri = getServerProfile().getServerUrl() + REST_SERVICES_V2_URI + REST_SERVER_INFO_URI; try { serverInfo = restTemplate.getForObject(uri, ServerInfo.class); @@ -408,24 +456,70 @@ public ResourceLookupsList getResourceLookups(String folderUri, boolean recursiv */ public ResourceLookupsList getResourceLookups(String folderUri, String query, List types, boolean recursive, int offset, int limit) throws RestClientException { + return getResourceLookups(folderUri, query, types, null, recursive, offset, limit); + } + + /** + * Retrieves the list of resource lookup objects for the resources contained in the given parent folder + * and matching the specified parameters. + * + * @param folderUri parent folder URI (e.g. /reports/samples/) + * @param query Match only resources having the specified text in the name or description. + * (can be null) + * @param types Match only resources of the given types. Multiple resource types allowed. + * (can be null) + * @param sortBy Represents a field in the results to sort by: uri, label, description, type, creationDate, + * updateDate, accessTime, or popularity (based on access events). + * (can be null) + * @param recursive Get resources recursively + * @param offset Pagination. Start index for requested page. + * @param limit Pagination. Resources count per page. + * @return the ResourceLookupsList value + * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors + */ + public ResourceLookupsList getResourceLookups(String folderUri, String query, List types, String sortBy, boolean recursive, + int offset, int limit) throws RestClientException { + ResourceLookupSearchCriteria criteria = new ResourceLookupSearchCriteria(); + criteria.setFolderUri(folderUri); + criteria.setQuery(query); + criteria.setTypes(types); + criteria.setSortBy(sortBy); + criteria.setRecursive(recursive); + criteria.setOffset(offset); + criteria.setLimit(limit); + return getResourceLookups(criteria); + } + + /** + * Retrieves the list of resource lookup objects matching the specified search criteria. + * + * @param searchCriteria the search criteria + * @return the ResourceLookupsList value + * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors + */ + public ResourceLookupsList getResourceLookups(ResourceLookupSearchCriteria searchCriteria) throws RestClientException { StringBuilder fullUri = new StringBuilder(); fullUri.append(getServerProfile().getServerUrl()) .append(REST_SERVICES_V2_URI) .append(REST_RESOURCES_URI) .append("?folderUri={folderUri}") .append("&q={query}") + .append("&sortBy={sortBy}") .append("&recursive={recursive}") + .append("&forceFullPage={forceFullPage}") .append("&offset={offset}") .append("&limit={limit}"); - if (types != null) { - for (String type : types) { + if (searchCriteria.getTypes() != null) { + for (String type : searchCriteria.getTypes()) { fullUri.append("&type=").append(type); } } ResponseEntity responseEntity = restTemplate.exchange(fullUri.toString(), HttpMethod.GET, - null, ResourceLookupsList.class, folderUri, query, recursive, offset, limit); + null, ResourceLookupsList.class, searchCriteria.getFolderUri(), searchCriteria.getQuery(), + searchCriteria.getSortBy(), searchCriteria.isRecursive(), searchCriteria.isForceFullPage(), + searchCriteria.getOffset(), searchCriteria.getLimit()); if (responseEntity.getStatusCode() == HttpStatus.NO_CONTENT) { return new ResourceLookupsList(); @@ -433,10 +527,28 @@ public ResourceLookupsList getResourceLookups(String folderUri, String query, Li ResourceLookupsList resourceLookupsList = responseEntity.getBody(); resourceLookupsList.setResultCount(responseEntity.getHeaders().getFirst("Result-Count")); resourceLookupsList.setTotalCount(responseEntity.getHeaders().getFirst("Total-Count")); + resourceLookupsList.setStartIndex(responseEntity.getHeaders().getFirst("Start-Index")); + resourceLookupsList.setNextOffset(responseEntity.getHeaders().getFirst("Next-Offset")); return resourceLookupsList; } } + /** + * Retrives all data for the root folder + */ + public FolderDataResponse getRootFolderData() { + String fullUri = jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_RESOURCES_URI; + HttpHeaders headers = new HttpHeaders(); + headers.add("Accept", "application/repository.folder+xml"); + headers.add("Content-Type", "application/xml"); + HttpEntity httpEntity = new HttpEntity("", headers); + + ResponseEntity responseEntity = restTemplate.exchange(fullUri, + HttpMethod.GET, httpEntity, FolderDataResponse.class); + + return responseEntity.getBody(); + } + //--------------------------------------------------------------------- // The Report Service //--------------------------------------------------------------------- @@ -446,8 +558,8 @@ public ResourceLookupsList getResourceLookups(String folderUri, String query, Li * with the ID of the saved output for downloading later with a GET request. * * @param resourceDescriptor resource descriptor of this report - * @param format The format of the report output. Possible values: PDF, HTML, XLS, RTF, CSV, - * XML, JRPRINT. The Default is PDF. + * @param format The format of the report output. Possible values: PDF, HTML, XLS, RTF, CSV, + * XML, JRPRINT. The Default is PDF. * @return ReportDescriptor * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors */ @@ -503,10 +615,9 @@ public void saveReportAttachmentToFile(String uuid, String name, File file) thro /** * Generates the fully qualified report URL to receive all pages report output in HTML format. * - * @param reportUri repository URI of the report + * @param reportUri repository URI of the report * @param parameters list of report parameter/input control values * @return the fully qualified report URL - * * @since 1.4 */ public String generateReportUrl(String reportUri, List parameters) { @@ -516,11 +627,10 @@ public String generateReportUrl(String reportUri, List paramete /** * Generates the fully qualified report URL to receive all pages report output in specified format. * - * @param reportUri repository URI of the report + * @param reportUri repository URI of the report * @param parameters list of report parameter/input control values - * @param format the format of the report output. Possible values: PDF, HTML, XLS, RTF, CSV, XML. + * @param format the format of the report output. Possible values: PDF, HTML, XLS, RTF, CSV, XML. * @return the fully qualified report URL - * * @since 1.4 */ public String generateReportUrl(String reportUri, List parameters, String format) { @@ -531,12 +641,11 @@ public String generateReportUrl(String reportUri, List paramete * Generates the fully qualified report URL according to specified parameters. The new v2/reports service allows clients * to receive report output in a single request-response using this url. * - * @param reportUri repository URI of the report + * @param reportUri repository URI of the report * @param parameters list of report parameter/input control values - * @param page a positive integer value used to output a specific page or 0 to output all pages - * @param format the format of the report output. Possible values: PDF, HTML, XLS, RTF, CSV, XML. + * @param page a positive integer value used to output a specific page or 0 to output all pages + * @param format the format of the report output. Possible values: PDF, HTML, XLS, RTF, CSV, XML. * @return the fully qualified report URL - * * @since 1.4 */ public String generateReportUrl(String reportUri, List parameters, int page, String format) { @@ -545,9 +654,9 @@ public String generateReportUrl(String reportUri, List paramete reportUrl.append(REST_REPORTS_URI).append(reportUri).append(".").append(format); if (parameters == null) parameters = new ArrayList(); - if(page > 0) parameters.add(new ReportParameter("page", Integer.toString(page))); + if (page > 0) parameters.add(new ReportParameter("page", Integer.toString(page))); - if (!parameters.isEmpty() ) { + if (!parameters.isEmpty()) { reportUrl.append("?"); Iterator paramIterator = parameters.iterator(); while (paramIterator.hasNext()) { @@ -557,7 +666,8 @@ public String generateReportUrl(String reportUri, List paramete try { String value = URLEncoder.encode(valueIterator.next(), "UTF-8"); reportUrl.append(parameter.getName()).append("=").append(value); - if (paramIterator.hasNext() || valueIterator.hasNext() ) reportUrl.append("&"); + if (paramIterator.hasNext() || valueIterator.hasNext()) + reportUrl.append("&"); } catch (UnsupportedEncodingException ex) { throw new IllegalArgumentException(ex); } @@ -571,9 +681,8 @@ public String generateReportUrl(String reportUri, List paramete * Downloads report output, once it has been generated and saves it in the specified file. * * @param reportUrl the fully qualified report URL - * @param file The file in which the output will be saved + * @param file The file in which the output will be saved * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.4 */ public void saveReportOutputToFile(String reportUrl, File file) throws RestClientException { @@ -591,38 +700,175 @@ public void saveReportOutputToFile(String reportUrl, File file) throws RestClien // Report Execution Service //--------------------------------------------------------------------- + /** + * Forms and executes url "{server url}/rest_v2/reportExecutions" + * + * @param request we delegate to the restTemplate. + * @return report execution response. Includes executionId for later use. + * @throws RestClientException + */ public ReportExecutionResponse runReportExecution(ReportExecutionRequest request) throws RestClientException { String url = jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS; return restTemplate.postForObject(url, request, ReportExecutionResponse.class); } - public URI getExportOuptutResourceURI(String executionId, String exportOutput) { - String outputResourceUri = "/{executionId}/exports/{exportOutput}/outputResource"; - String fullUri = jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS + outputResourceUri; + /** + * Sends request with porpose to fetch current export datum. + * + * @param executionId Identifies current id of running report. + * @param request we delegate to the restTemplate. + * @return response with all exports datum associated with request. + * @throws RestClientException + */ + public ExportExecution runExportForReport(String executionId, ExportsRequest request) throws RestClientException { + return restTemplate.postForObject(getExportForReportURI(executionId), request, ExportExecution.class); + } - UriTemplate uriTemplate = new UriTemplate(fullUri); - return uriTemplate.expand(executionId, exportOutput); + /** + * Generates link for requesting data on specified export resource. + * + * @param executionId Identifies current id of running report. + * @return "{server url}/rest_v2/reportExecutions/{executionId}/exports" + */ + public URI getExportForReportURI(String executionId) { + String outputResourceUri = "/{executionId}"; + String fullUri = jsServerProfile.getServerUrl() + + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS + + outputResourceUri + REST_REPORT_EXPORTS; + + return new UriTemplate(fullUri).expand(executionId, executionId); + } + + /** + * Sends request for the current running report for the status check. + * + * @param executionId Identifies current id of running report. + * @return response which expose current report status. + */ + public ReportStatusResponse runReportStatusCheck(String executionId) { + return restTemplate.getForObject(getReportStatusCheckURI(executionId), ReportStatusResponse.class); } + /** + * Generates link for requesting report execution status. + * + * @param executionId Identifies current id of running report. + * @return "{server url}/rest_v2/reportExecutions/{executionId}/status" + */ + public URI getReportStatusCheckURI(String executionId) { + String outputResourceUri = "/{executionId}"; + + String fullUri = jsServerProfile.getServerUrl() + + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS + + outputResourceUri + REST_REPORT_STATUS; + + return new UriTemplate(fullUri).expand(executionId); + } + + /** + * Saves resource ouput in file. + * + * @param executionId Identifies current id of running report. + * @param exportOutput Identifier which refers to current requested export. + * @param file The file in which the output will be saved + * @throws RestClientException + */ public void saveExportOutputToFile(String executionId, String exportOutput, File file) throws RestClientException { - URI outputResourceUri = getExportOuptutResourceURI(executionId, exportOutput); + URI outputResourceUri = getExportOutputResourceURI(executionId, exportOutput); downloadFile(outputResourceUri, file); } - public URI getExportAttachmentURI(String executionId, String exportOutput, String attachmentName) { - String attachmentUri = "/{executionId}/exports/{exportOutput}/attachments/{attachment}"; - String fullUri = jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS + attachmentUri; + /** + * Load output data for export on current request. + * + * @param executionId Identifies current id of running report. + * @param exportOutput Identifier which refers to current requested export. + * @return Basically it will be 3 cases HTML/JSON/XML types. + */ + public ReportDataResponse runExportOutputResource(String executionId, String exportOutput) { + ResponseEntity response = restTemplate.exchange( + getExportOutputResourceURI(executionId, exportOutput), HttpMethod.GET, null, String.class); + + boolean isFinal; + boolean hasOutputFinal = response.getHeaders().containsKey("output-final"); + String data = response.getBody(); + + if (hasOutputFinal) { + isFinal = Boolean.valueOf(response.getHeaders().getFirst("output-final")); + } else { + // "output-final" header is missing for JRS 5.5 and lower, + // so we consider request to be not final by default + isFinal = false; + } + return new ReportDataResponse(isFinal, data); + } + + /** + * Generates link for requesting report output resource datum. + * + * @param executionId Identifies current id of running report. + * @param exportOutput Identifier which refers to current requested export. + * @return "{server url}/rest_v2/reportExecutions/{executionId}/exports/{exportOutput}/outputResource" + */ + public URI getExportOutputResourceURI(String executionId, String exportOutput) { + String outputResourceUri = "/{executionId}/exports/{exportOutput}/outputResource"; + String fullUri = jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS + outputResourceUri; UriTemplate uriTemplate = new UriTemplate(fullUri); - return uriTemplate.expand(executionId, exportOutput, attachmentName); + return uriTemplate.expand(executionId, exportOutput); } + /** + * Save report in file with specified name. + * + * @param executionId Identifies current id of running report. + * @param exportOutput Identifier which refers to current requested export. + * @param attachmentName Name of attachment we store on JRS side. + * @param file The file in which the output will be saved + * @throws RestClientException + */ public void saveExportAttachmentToFile(String executionId, String exportOutput, String attachmentName, File file) throws RestClientException { URI attachmentUri = getExportAttachmentURI(executionId, exportOutput, attachmentName); downloadFile(attachmentUri, file); } + /** + * Generates link for requesting of report export attachemnt data. + * + * @param executionId Identifies current id of running report. + * @param exportOutput Identifier which refers to current requested export. + * @param attachmentName Name of attachment we store on JRS side. + * @return "{server url}/rest_v2/reportExecutions/{executionId}/exports/{exportOutput}/attachments/{attachment}" + */ + public URI getExportAttachmentURI(String executionId, String exportOutput, String attachmentName) { + String attachmentUri = "/{executionId}/exports/{exportOutput}/attachments/{attachment}"; + String fullUri = jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS + attachmentUri; + return new UriTemplate(fullUri).expand(executionId, exportOutput, attachmentName); + } + + /** + * Sends request for retrieving report details data. + * + * @param executionId Identifies current id of running report. + * @return response which expose current report details. + */ + public ReportExecutionResponse runReportDetailsRequest(String executionId) { + return restTemplate.getForObject(getReportDetailsURI(executionId), ReportExecutionResponse.class); + } + + /** + * Generates link for requesting details on specified report. + * + * @param executionId Identifies current id of running report. + * @return "{server url}/rest_v2/reportExecutions/{executionId}" + */ + public URI getReportDetailsURI(String executionId) { + String attachmentUri = "/{executionId}"; + String fullUri = jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_REPORT_EXECUTIONS + attachmentUri; + return new UriTemplate(fullUri).expand(executionId); + } + //--------------------------------------------------------------------- // Input Controls //--------------------------------------------------------------------- @@ -631,9 +877,9 @@ public void saveExportAttachmentToFile(String executionId, String exportOutput, * Gets the resource descriptor of a query-based input control that contains query data * according to specified parameters. * - * @param uri repository URI of the input control + * @param uri repository URI of the input control * @param datasourceUri repository URI of a datasource for the control - * @param params parameters for the input control (can be null) + * @param params parameters for the input control (can be null) * @return the ResourceDescriptor of a query-based input control that contains query data * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors */ @@ -642,7 +888,7 @@ public ResourceDescriptor getInputControlWithQueryData(String uri, String dataso fullUri.append(restServicesUrl).append(REST_RESOURCE_URI).append(uri); fullUri.append("?IC_GET_QUERY_DATA=").append(datasourceUri); if (params != null) { - for(ResourceParameter parameter : params) { + for (ResourceParameter parameter : params) { fullUri.append(parameter.isListItem() ? "&PL_" : "&P_"); fullUri.append(parameter.getName()).append("=").append(parameter.getValue()); } @@ -653,9 +899,9 @@ public ResourceDescriptor getInputControlWithQueryData(String uri, String dataso /** * Gets the query data of a query-based input control, according to specified parameters. * - * @param uri repository URI of the input control + * @param uri repository URI of the input control * @param datasourceUri repository URI of a datasource for the control - * @param params parameters for the input control (can be null) + * @param params parameters for the input control (can be null) * @return The query data as list of ResourceProperty objects * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors */ @@ -673,8 +919,8 @@ public List getInputControlQueryData(String uri, String dataso property.setName(queryDataRow.getValue()); //cols StringBuilder value = new StringBuilder(); - for(ResourceProperty queryDataCol : queryDataRow.getProperties()) { - if(ResourceDescriptor.PROP_QUERY_DATA_ROW_COLUMN.equals(queryDataCol.getName())) { + for (ResourceProperty queryDataCol : queryDataRow.getProperties()) { + if (ResourceDescriptor.PROP_QUERY_DATA_ROW_COLUMN.equals(queryDataCol.getName())) { if (value.length() > 0) value.append(" | "); value.append(queryDataCol.getValue()); } @@ -697,7 +943,6 @@ public List getInputControlQueryData(String uri, String dataso * @param reportUri repository URI of the report * @return a list of input controls * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public List getInputControls(String reportUri) throws RestClientException { @@ -708,12 +953,11 @@ public List getInputControls(String reportUri) throws RestClientEx * Gets the list of input controls with specified IDs for the report with specified URI * and according to selected values. * - * @param reportUri repository URI of the report - * @param controlsIds list of input controls IDs + * @param reportUri repository URI of the report + * @param controlsIds list of input controls IDs * @param selectedValues list of selected values * @return a list of input controls * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public List getInputControls(String reportUri, List controlsIds, @@ -727,7 +971,6 @@ public List getInputControls(String reportUri, List contro * @param reportUri repository URI of the report * @return the InputControlsList value * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public InputControlsList getInputControlsList(String reportUri) throws RestClientException { @@ -738,16 +981,15 @@ public InputControlsList getInputControlsList(String reportUri) throws RestClien * Gets the list of input controls with specified IDs for the report with specified URI * and according to selected values. * - * @param reportUri repository URI of the report - * @param controlsIds list of input controls IDs + * @param reportUri repository URI of the report + * @param controlsIds list of input controls IDs * @param selectedValues list of selected values * @return the InputControlsList value * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public InputControlsList getInputControlsList(String reportUri, List controlsIds, - List selectedValues) throws RestClientException { + List selectedValues) throws RestClientException { // generate full url String url = generateInputControlsUrl(reportUri, controlsIds, false); // add selected values to request @@ -765,7 +1007,6 @@ public InputControlsList getInputControlsList(String reportUri, List con * @param reportUri repository URI of the report * @return the list of the input controls states * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public List getInputControlsValues(String reportUri) throws RestClientException { @@ -776,16 +1017,15 @@ public List getInputControlsValues(String reportUri) throws R * Gets the list of states of input controls with specified IDs for the report with specified URI * and according to selected values. * - * @param reportUri repository URI of the report - * @param controlsIds list of input controls IDs + * @param reportUri repository URI of the report + * @param controlsIds list of input controls IDs * @param selectedValues list of selected values * @return the list of the input controls states * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * - * @since 1.6 + * @since 1.6 */ public List getInputControlsValues(String reportUri, List controlsIds, - List selectedValues) throws RestClientException { + List selectedValues) throws RestClientException { return getInputControlsValuesList(reportUri, controlsIds, selectedValues).getInputControlStates(); } @@ -795,7 +1035,6 @@ public List getInputControlsValues(String reportUri, List controlsIds, - List selectedValues) throws RestClientException { + List selectedValues) throws RestClientException { // generate full url String url = generateInputControlsUrl(reportUri, controlsIds, true); // add selected values to request @@ -823,20 +1061,19 @@ public InputControlStatesList getInputControlsValuesList(String reportUri, List< parametersList.setReportParameters(selectedValues); // execute POST request try { - return restTemplate.postForObject(url, parametersList, InputControlStatesList.class); + return restTemplate.postForObject(url, parametersList, InputControlStatesList.class); } catch (HttpMessageNotReadableException exception) { - return new InputControlStatesList(); + return new InputControlStatesList(); } } /** * Validates the input controls values on the server side and returns states only for invalid controls. * - * @param reportUri repository URI of the report + * @param reportUri repository URI of the report * @param inputControls list of input controls that should be validated * @return the list of the input controls states * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.4 */ public List validateInputControlsValues(String reportUri, List inputControls) @@ -847,34 +1084,32 @@ public List validateInputControlsValues(String reportUri, Lis /** * Validates the input controls values on the server side and returns states only for invalid controls. * - * @param reportUri repository URI of the report - * @param controlsIds list of input controls IDs that should be validated + * @param reportUri repository URI of the report + * @param controlsIds list of input controls IDs that should be validated * @param selectedValues list of selected values for validation * @return the list of the input controls states * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public List validateInputControlsValues(String reportUri, List controlsIds, - List selectedValues) throws RestClientException { + List selectedValues) throws RestClientException { return validateInputControlsValuesList(reportUri, controlsIds, selectedValues).getInputControlStates(); } /** * Validates the input controls values on the server side and returns states only for invalid controls. * - * @param reportUri repository URI of the report + * @param reportUri repository URI of the report * @param inputControls list of input controls that should be validated * @return the InputControlStatesList value * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public InputControlStatesList validateInputControlsValuesList(String reportUri, List inputControls) throws RestClientException { List controlsIds = new ArrayList(); List selectedValues = new ArrayList(); - for(InputControl control : inputControls) { + for (InputControl control : inputControls) { controlsIds.add(control.getId()); selectedValues.add(new ReportParameter(control.getId(), control.getSelectedValues())); } @@ -885,27 +1120,59 @@ public InputControlStatesList validateInputControlsValuesList(String reportUri, /** * Validates the input controls values on the server side and returns states only for invalid controls. * - * @param reportUri repository URI of the report - * @param controlsIds list of input controls IDs that should be validated + * @param reportUri repository URI of the report + * @param controlsIds list of input controls IDs that should be validated * @param selectedValues list of selected values for validation * @return the InputControlStatesList value * @throws RestClientException thrown by RestTemplate whenever it encounters client-side HTTP errors - * * @since 1.6 */ public InputControlStatesList validateInputControlsValuesList(String reportUri, List controlsIds, - List selectedValues) throws RestClientException { + List selectedValues) throws RestClientException { InputControlStatesList statesList = getInputControlsValuesList(reportUri, controlsIds, selectedValues); // remove states without validation errors Iterator iterator = statesList.getInputControlStates().iterator(); - while(iterator.hasNext()) { - if(iterator.next().getError() == null) { + while (iterator.hasNext()) { + if (iterator.next().getError() == null) { iterator.remove(); } } return statesList; } + /** + * Method which flashes all stared cookies. + */ + public static void flushCookies() { + StaticCacheHelper.clearCache(); + } + + //--------------------------------------------------------------------- + // Thumbnails API + //--------------------------------------------------------------------- + + /** + * Returns thumbnail image or encoded image of the requested URI without placeholder + * + * @param resourceUri Uri of resource + * @return {serverUrl}/rest_v2/thumbnails/{resourceUri}?defaultAllowed=false + */ + public String generateThumbNailUri(String resourceUri) { + return generateThumbNailUri(resourceUri, false); + } + + /** + * Returns thumbnail image or encoded image of the requested URI + * + * @param resourceUri Uri of resource + * @param defaultAllowed If true, a placeholder thumbnail will be provided when no thumbnail is available (default: false) + * @return {serverUrl}/rest_v2/thumbnails/{resourceUri}?defaultAllowed={allowedFlag} + */ + public String generateThumbNailUri(String resourceUri, boolean defaultAllowed) { + return jsServerProfile.getServerUrl() + REST_SERVICES_V2_URI + REST_THUMBNAILS + + resourceUri + "?defaultAllowed=" + Boolean.toString(defaultAllowed); + } + //--------------------------------------------------------------------- // Helper methods //--------------------------------------------------------------------- @@ -940,13 +1207,11 @@ private void updateRequestFactoryTimeouts() { } private void updateConnectTimeout() { - SimpleClientHttpRequestFactory factory = (SimpleClientHttpRequestFactory) getRestTemplate().getRequestFactory(); - factory.setConnectTimeout(connectTimeout); + requestFactory.setConnectTimeout(connectTimeout); } private void updateReadTimeout() { - SimpleClientHttpRequestFactory factory = (SimpleClientHttpRequestFactory) getRestTemplate().getRequestFactory(); - factory.setReadTimeout(readTimeout); + requestFactory.setReadTimeout(readTimeout); } private String generateInputControlsUrl(String reportUri, List controlsIds, boolean valuesOnly) { @@ -970,6 +1235,24 @@ private String generateInputControlsUrl(String reportUri, List controlsI return fullUri.toString(); } + private void fetchXmlConverter() { + List> converters = restTemplate.getMessageConverters(); + for (HttpMessageConverter converter : converters) { + if (converter instanceof SimpleXmlHttpMessageConverter) { + simpleXmlHttpMessageConverter = + (SimpleXmlHttpMessageConverter) converter; + } + } + } + + private void configureAnnotationStrategy() { + if (simpleXmlHttpMessageConverter != null) { + Strategy annotationStrategy = new AnnotationStrategy(); + Serializer serializer = new Persister(annotationStrategy); + simpleXmlHttpMessageConverter.setSerializer(serializer); + } + } + //--------------------------------------------------------------------- // Getters & Setters //--------------------------------------------------------------------- diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/JsServerProfile.java b/client/src/main/java/com/jaspersoft/android/sdk/client/JsServerProfile.java index a35d97b9..05a23e30 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/JsServerProfile.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/JsServerProfile.java @@ -139,4 +139,31 @@ public void setPassword(String password) { this.password = password; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JsServerProfile that = (JsServerProfile) o; + + if (!alias.equals(that.alias)) return false; + if (organization != null ? !organization.equals(that.organization) : that.organization != null) + return false; + if (!password.equals(that.password)) return false; + if (!serverUrl.equals(that.serverUrl)) return false; + if (!username.equals(that.username)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + alias.hashCode(); + result = 31 * result + serverUrl.hashCode(); + result = 31 * result + (organization != null ? organization.hashCode() : 0); + result = 31 * result + username.hashCode(); + result = 31 * result + password.hashCode(); + return result; + } } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsAsyncTaskManager.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsAsyncTaskManager.java index 2db9ab6d..94887031 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsAsyncTaskManager.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsAsyncTaskManager.java @@ -32,6 +32,7 @@ import android.os.Build; import android.util.Log; import android.view.WindowManager; + import com.jaspersoft.android.sdk.client.async.task.JsAsyncTask; import java.util.ArrayList; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsXmlSpiceService.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsXmlSpiceService.java index f1fb7340..38c243dc 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsXmlSpiceService.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/JsXmlSpiceService.java @@ -25,10 +25,12 @@ package com.jaspersoft.android.sdk.client.async; import android.app.Application; + import com.octo.android.robospice.SpiceService; import com.octo.android.robospice.persistence.CacheManager; import com.octo.android.robospice.persistence.exception.CacheCreationException; import com.octo.android.robospice.persistence.springandroid.xml.SimpleSerializerObjectPersisterFactory; +import com.octo.android.robospice.persistence.string.InFileStringObjectPersister; /** * This class offers a {@link SpiceService} dedicated to xml web services. Provides @@ -42,6 +44,8 @@ public class JsXmlSpiceService extends SpiceService { @Override public CacheManager createCacheManager(Application application) throws CacheCreationException { CacheManager cacheManager = new CacheManager(); + // It is really important to keep proper persister order. + cacheManager.addPersister(new InFileStringObjectPersister(application)); cacheManager.addPersister(new SimpleSerializerObjectPersisterFactory(application)); return cacheManager; } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/BaseRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/BaseRequest.java index f65055e7..e55fa8ef 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/BaseRequest.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/BaseRequest.java @@ -27,6 +27,7 @@ import com.jaspersoft.android.sdk.client.JsRestClient; import com.octo.android.robospice.request.SpiceRequest; import com.octo.android.robospice.retry.DefaultRetryPolicy; + import roboguice.util.temp.Ln; /** diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/CheckReportStatusRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/CheckReportStatusRequest.java new file mode 100644 index 00000000..1151c995 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/CheckReportStatusRequest.java @@ -0,0 +1,41 @@ +package com.jaspersoft.android.sdk.client.async.request; + +import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.oxm.report.ReportStatusResponse; + +/** + * @author Tom Koptel + * @since 1.9 + * + * Check the status of export execution. + */ +public class CheckReportStatusRequest extends BaseRequest { + private String executionId; + + /** + * + * @param jsRestClient Rest client. Encapsulates call logic + * @param executionId Current report identifier. + */ + public CheckReportStatusRequest(JsRestClient jsRestClient, String executionId) { + super(jsRestClient, ReportStatusResponse.class); + this.executionId = executionId; + } + + public CheckReportStatusRequest(JsRestClient jsRestClient) { + super(jsRestClient, ReportStatusResponse.class); + } + + @Override + public ReportStatusResponse loadDataFromNetwork() throws Exception { + return getJsRestClient().runReportStatusCheck(executionId); + } + + public String getExportExecutionId() { + return executionId; + } + + public void setExportExecutionId(String exportExecutionId) { + this.executionId = exportExecutionId; + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/GetRootFolderDataRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/GetRootFolderDataRequest.java new file mode 100644 index 00000000..003bd697 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/GetRootFolderDataRequest.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.jaspersoft.android.sdk.client.async.request; + +import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.async.request.cacheable.CacheableRequest; +import com.jaspersoft.android.sdk.client.oxm.report.FolderDataResponse; + +public class GetRootFolderDataRequest extends CacheableRequest { + + public GetRootFolderDataRequest(JsRestClient jsRestClient) { + super(jsRestClient, FolderDataResponse.class); + } + + @Override + public FolderDataResponse loadDataFromNetwork() throws Exception { + return getJsRestClient().getRootFolderData(); + } + +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/ReportDetailsRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/ReportDetailsRequest.java new file mode 100644 index 00000000..982e3c54 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/ReportDetailsRequest.java @@ -0,0 +1,26 @@ +package com.jaspersoft.android.sdk.client.async.request; + +import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.oxm.report.ReportExecutionResponse; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class ReportDetailsRequest extends BaseRequest { + private String executionId; + + public ReportDetailsRequest(JsRestClient jsRestClient) { + super(jsRestClient, ReportExecutionResponse.class); + } + + public ReportDetailsRequest(JsRestClient jsRestClient, String executionId) { + super(jsRestClient, ReportExecutionResponse.class); + this.executionId = executionId; + } + + @Override + public ReportExecutionResponse loadDataFromNetwork() throws Exception { + return getJsRestClient().runReportDetailsRequest(executionId); + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/RunReportExportOutputRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/RunReportExportOutputRequest.java new file mode 100644 index 00000000..5a492681 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/RunReportExportOutputRequest.java @@ -0,0 +1,44 @@ +package com.jaspersoft.android.sdk.client.async.request; + +import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.oxm.report.ReportDataResponse; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class RunReportExportOutputRequest extends BaseRequest { + private String requestId; + private String executionId; + + public RunReportExportOutputRequest(JsRestClient jsRestClient) { + super(jsRestClient, ReportDataResponse.class); + } + + public RunReportExportOutputRequest(JsRestClient jsRestClient, String requestId, String executionId) { + super(jsRestClient, ReportDataResponse.class); + this.requestId = requestId; + this.executionId = executionId; + } + + @Override + public ReportDataResponse loadDataFromNetwork() throws Exception { + return getJsRestClient().runExportOutputResource(requestId, executionId); + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getExecutionId() { + return executionId; + } + + public void setExecutionId(String executionId) { + this.executionId = executionId; + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/RunReportExportsRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/RunReportExportsRequest.java new file mode 100644 index 00000000..f5171ecb --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/RunReportExportsRequest.java @@ -0,0 +1,51 @@ +package com.jaspersoft.android.sdk.client.async.request; + +import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.oxm.report.ExportExecution; +import com.jaspersoft.android.sdk.client.oxm.report.ExportsRequest; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class RunReportExportsRequest extends BaseRequest { + + private ExportsRequest request; + private String executionId; + + public RunReportExportsRequest(JsRestClient jsRestClient) { + super(jsRestClient, ExportExecution.class); + } + + public RunReportExportsRequest(JsRestClient jsRestClient, + ExportsRequest request, String executionId) { + super(jsRestClient, ExportExecution.class); + this.request = request; + this.executionId = executionId; + } + + @Override + public ExportExecution loadDataFromNetwork() throws Exception { + return getJsRestClient().runExportForReport(executionId, request); + } + + //--------------------------------------------------------------------- + // Getters & Setters + //--------------------------------------------------------------------- + + public ExportsRequest getRequest() { + return request; + } + + public void setRequest(ExportsRequest request) { + this.request = request; + } + + public String getExecutionId() { + return executionId; + } + + public void setExecutionId(String executionId) { + this.executionId = executionId; + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/cacheable/GetResourceLookupsRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/cacheable/GetResourceLookupsRequest.java index 4e62f1a4..8b0e046c 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/cacheable/GetResourceLookupsRequest.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/request/cacheable/GetResourceLookupsRequest.java @@ -25,6 +25,7 @@ package com.jaspersoft.android.sdk.client.async.request.cacheable; import com.jaspersoft.android.sdk.client.JsRestClient; +import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookupSearchCriteria; import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookupsList; import java.util.List; @@ -38,12 +39,7 @@ */ public class GetResourceLookupsRequest extends CacheableRequest { - private String folderUri; - private String query; - private List types; - private boolean recursive; - private int offset; - private int limit; + private ResourceLookupSearchCriteria searchCriteria; /** * Creates a new instance of {@link GetResourceLookupsRequest}. @@ -84,53 +80,70 @@ public GetResourceLookupsRequest(JsRestClient jsRestClient, String folderUri, Li */ public GetResourceLookupsRequest(JsRestClient jsRestClient, String folderUri, String query, List types, boolean recursive, int offset, int limit) { + this(jsRestClient, folderUri, query, types, null, recursive, offset, limit); + } + + /** + * Creates a new instance of {@link GetResourceLookupsRequest}. + * + * @param folderUri parent folder URI (e.g. /reports/samples/) + * @param query Match only resources having the specified text in the name or description. + * (can be null) + * @param types Match only resources of the given types. Multiple resource types allowed. + * (can be null) + * @param sortBy Represents a field in the results to sort by: uri, label, description, type, creationDate, + * updateDate, accessTime, or popularity (based on access events). + * (can be null) + * @param recursive Get resources recursively + * @param offset Pagination. Start index for requested page. + * @param limit Pagination. Resources count per page. + */ + public GetResourceLookupsRequest(JsRestClient jsRestClient, String folderUri, String query, List types, + String sortBy, boolean recursive, int offset, int limit) { super(jsRestClient, ResourceLookupsList.class); - this.folderUri = folderUri; - this.query = query; - this.types = types; - this.recursive = recursive; - this.offset = offset; - this.limit = limit; + searchCriteria = new ResourceLookupSearchCriteria(); + searchCriteria.setFolderUri(folderUri); + searchCriteria.setQuery(query); + searchCriteria.setTypes(types); + searchCriteria.setSortBy(sortBy); + searchCriteria.setRecursive(recursive); + searchCriteria.setOffset(offset); + searchCriteria.setLimit(limit); } + /** + * Creates a new instance of {@link GetResourceLookupsRequest}. + * + * @param searchCriteria the search criteria + */ + public GetResourceLookupsRequest(JsRestClient jsRestClient, ResourceLookupSearchCriteria searchCriteria) { + super(jsRestClient, ResourceLookupsList.class); + this.searchCriteria = searchCriteria; + } @Override public ResourceLookupsList loadDataFromNetwork() throws Exception { - return getJsRestClient().getResourceLookups(folderUri, query, types, recursive, offset, limit); + return getJsRestClient().getResourceLookups(searchCriteria); } @Override protected String createCacheKeyString() { - return super.createCacheKeyString() + folderUri + query + types + recursive + offset + limit; + return super.createCacheKeyString() + + searchCriteria.getFolderUri() + + searchCriteria.getQuery() + + searchCriteria.getTypes() + + searchCriteria.getSortBy() + + searchCriteria.isRecursive() + + searchCriteria.getOffset() + + searchCriteria.getLimit(); } //--------------------------------------------------------------------- // Getters & Setters //--------------------------------------------------------------------- - - public String getFolderUri() { - return folderUri; - } - - public String getQuery() { - return query; - } - - public List getTypes() { - return types; - } - - public boolean isRecursive() { - return recursive; - } - - public int getOffset() { - return offset; - } - - public int getLimit() { - return limit; + public ResourceLookupSearchCriteria getSearchCriteria() { + return searchCriteria; } } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/async/task/JsAsyncTask.java b/client/src/main/java/com/jaspersoft/android/sdk/client/async/task/JsAsyncTask.java index 6c14cdb6..53fc8bf3 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/async/task/JsAsyncTask.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/async/task/JsAsyncTask.java @@ -25,6 +25,7 @@ package com.jaspersoft.android.sdk.client.async.task; import android.os.AsyncTask; + import com.jaspersoft.android.sdk.client.async.JsProgressTracker; import java.util.Timer; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/ic/InputControlWrapper.java b/client/src/main/java/com/jaspersoft/android/sdk/client/ic/InputControlWrapper.java index 87dbbd7e..c010bb42 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/ic/InputControlWrapper.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/ic/InputControlWrapper.java @@ -25,6 +25,7 @@ package com.jaspersoft.android.sdk.client.ic; import android.view.View; + import com.jaspersoft.android.sdk.client.oxm.ResourceDescriptor; import com.jaspersoft.android.sdk.client.oxm.ResourceParameter; import com.jaspersoft.android.sdk.client.oxm.ResourceProperty; @@ -41,6 +42,7 @@ * @version $Id$ * @since 1.0 */ +@Deprecated public class InputControlWrapper { public static final String NULL_SUBSTITUTE = "~NULL~"; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/ResourceDescriptor.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/ResourceDescriptor.java index 5983aff9..551536ad 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/ResourceDescriptor.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/ResourceDescriptor.java @@ -22,6 +22,7 @@ package com.jaspersoft.android.sdk.client.oxm; import android.util.Log; + import org.simpleframework.xml.Attribute; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControl.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControl.java index 235793c5..c7407174 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControl.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControl.java @@ -27,8 +27,10 @@ import android.os.Parcel; import android.os.Parcelable; import android.view.View; + import com.jaspersoft.android.sdk.client.oxm.control.validation.ValidationRule; import com.jaspersoft.android.sdk.client.oxm.control.validation.ValidationRulesList; + import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Root; @@ -50,6 +52,7 @@ public enum Type { bool, singleValueText, singleValueNumber, + singleValueTime, singleValueDate, singleValueDatetime, singleSelect, @@ -155,6 +158,7 @@ public Set getSelectedValues() { case bool: case singleValueText: case singleValueNumber: + case singleValueTime: case singleValueDate: case singleValueDatetime: if (getState().getValue() != null) { diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlOption.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlOption.java index 3edff252..b20e4233 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlOption.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlOption.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; + import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlState.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlState.java index b931eeb9..df029a05 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlState.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/InputControlState.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; + import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Root; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/DateTimeFormatValidationRule.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/DateTimeFormatValidationRule.java index 6026beb4..66e4d4cd 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/DateTimeFormatValidationRule.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/DateTimeFormatValidationRule.java @@ -25,6 +25,7 @@ package com.jaspersoft.android.sdk.client.oxm.control.validation; import android.os.Parcel; + import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/MandatoryValidationRule.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/MandatoryValidationRule.java index f67e2325..a4f1a841 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/MandatoryValidationRule.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/MandatoryValidationRule.java @@ -25,6 +25,7 @@ package com.jaspersoft.android.sdk.client.oxm.control.validation; import android.os.Parcel; + import org.simpleframework.xml.Root; /** diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRule.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRule.java index 598a80a3..34b5d726 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRule.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRule.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; + import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRulesList.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRulesList.java index 82bbfeaa..0f407ca3 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRulesList.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/control/validation/ValidationRulesList.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; + import org.simpleframework.xml.ElementList; import org.simpleframework.xml.ElementListUnion; import org.simpleframework.xml.Root; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/converter/ReportStatusConverter.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/converter/ReportStatusConverter.java new file mode 100644 index 00000000..baa74b47 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/converter/ReportStatusConverter.java @@ -0,0 +1,23 @@ +package com.jaspersoft.android.sdk.client.oxm.converter; + +import com.jaspersoft.android.sdk.client.oxm.report.ReportStatusResponse; + +import org.simpleframework.xml.convert.Converter; +import org.simpleframework.xml.stream.InputNode; +import org.simpleframework.xml.stream.OutputNode; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class ReportStatusConverter implements Converter { + @Override + public ReportStatusResponse read(InputNode node) throws Exception { + return new ReportStatusResponse(node.getValue()); + } + + @Override + public void write(OutputNode node, ReportStatusResponse value) throws Exception { + // Do nothing + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ErrorDescriptor.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ErrorDescriptor.java new file mode 100644 index 00000000..b2106631 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ErrorDescriptor.java @@ -0,0 +1,49 @@ +package com.jaspersoft.android.sdk.client.oxm.report; + +import org.simpleframework.xml.Element; +import org.simpleframework.xml.Root; +import org.simpleframework.xml.Serializer; +import org.simpleframework.xml.core.Persister; +import org.springframework.web.client.HttpStatusCodeException; + +import java.io.StringWriter; + +/** + * @author Tom Koptel + * @since 1.9 + */ +@Root(strict = false) +public class ErrorDescriptor { + @Element + private String errorCode; + @Element(required = false) + private String message; + + public static ErrorDescriptor valueOf(HttpStatusCodeException exception) { + String response = exception.getResponseBodyAsString(); + Serializer serializer = new Persister(); + StringWriter stringWriter = new StringWriter(); + stringWriter.append(response); + try { + return serializer.read(ErrorDescriptor.class, response); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExecutionRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExecutionRequest.java new file mode 100644 index 00000000..b96dfc46 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExecutionRequest.java @@ -0,0 +1,172 @@ +package com.jaspersoft.android.sdk.client.oxm.report; + +import org.simpleframework.xml.Element; +import org.simpleframework.xml.ElementList; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.List; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class ExecutionRequest { + public static final String DEFAULT_ATTACHMENT_PREFIX = "/reportExecutions/{reportExecutionId}/exports/{exportExecutionId}/attachments/"; + public static final String MARKUP_TYPE_EMBEDDABLE = "embeddable"; + public static final String MARKUP_TYPE_FULL = "full"; + + @Element(required=false) + protected String reportUnitUri; + + @Element(required=false) + protected String markupType; + + @Element(required=false) + protected String baseUrl; + + @Element(required=false) + protected Boolean async; + + @Element(required=false) + protected Boolean freshData; + + @Element(required=false) + protected Boolean saveDataSnapshot; + + @Element + protected String outputFormat; + + @Element(required=false) + protected Boolean interactive; + + @Element(required=false) + protected Boolean ignorePagination; + + @Element(required=false) + protected Boolean allowInlineScripts; + + @Element(required=false) + protected String pages; + + @Element(required=false) + protected String attachmentsPrefix; + + @ElementList(required=false) + protected List parameters; + + public void setAttachmentsPrefix(String attachmentsPrefix) { + this.attachmentsPrefix = attachmentsPrefix; + } + + public void setEscapedAttachmentsPrefix(String attachmentsPrefix) { + try { + this.attachmentsPrefix = URLEncoder.encode(attachmentsPrefix, "UTF-8"); + } catch (UnsupportedEncodingException exception) { + this.attachmentsPrefix = attachmentsPrefix; + } catch (NullPointerException exception) { + this.attachmentsPrefix = attachmentsPrefix; + } + } + + public String getAttachmentsPrefix() { + return attachmentsPrefix; + } + + public String getReportUnitUri() { + return reportUnitUri; + } + + public void setReportUnitUri(String reportUnitUri) { + this.reportUnitUri = reportUnitUri; + } + + public boolean isAsync() { + return async; + } + + public void setAsync(boolean async) { + this.async = async; + } + + public boolean isFreshData() { + return freshData; + } + + public void setFreshData(boolean freshData) { + this.freshData = freshData; + } + + public boolean isSaveDataSnapshot() { + return saveDataSnapshot; + } + + public void setSaveDataSnapshot(boolean saveDataSnapshot) { + this.saveDataSnapshot = saveDataSnapshot; + } + + public String getOutputFormat() { + return outputFormat; + } + + public void setOutputFormat(String outputFormat) { + this.outputFormat = outputFormat; + } + + public boolean isInteractive() { + return interactive; + } + + public void setInteractive(boolean interactive) { + this.interactive = interactive; + } + + public boolean isIgnorePagination() { + return ignorePagination; + } + + public void setIgnorePagination(boolean ignorePagination) { + this.ignorePagination = ignorePagination; + } + + public String getPages() { + return pages; + } + + public void setPages(String pages) { + this.pages = pages; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getMarkupType() { + return markupType; + } + + public void setMarkupType(String markupType) { + this.markupType = markupType; + } + + public Boolean getAllowInlineScripts() { + return allowInlineScripts; + } + + public void setAllowInlineScripts(Boolean allowInlineScripts) { + this.allowInlineScripts = allowInlineScripts; + } + +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExportExecution.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExportExecution.java index 9bb22818..c89299e5 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExportExecution.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExportExecution.java @@ -44,7 +44,7 @@ public class ExportExecution { @Element private String status; - @Element + @Element(required=false) private ReportOutputResource outputResource; @ElementList(empty=false, entry="attachment", required=false) diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExportsRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExportsRequest.java new file mode 100644 index 00000000..8801e530 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ExportsRequest.java @@ -0,0 +1,11 @@ +package com.jaspersoft.android.sdk.client.oxm.report; + +import org.simpleframework.xml.Root; + +/** + * @author Tom Koptel + * @since 1.9 + */ +@Root(name="export") +public class ExportsRequest extends ExecutionRequest { +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/FolderDataResponse.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/FolderDataResponse.java new file mode 100644 index 00000000..86693034 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/FolderDataResponse.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.jaspersoft.android.sdk.client.oxm.report; + +import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookup; + +import org.simpleframework.xml.Root; + +@Root(name = "folder") +public class FolderDataResponse extends ResourceLookup { + public FolderDataResponse() { + this.resourceType = ResourceType.folder.toString(); + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportDataResponse.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportDataResponse.java new file mode 100644 index 00000000..11a11834 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportDataResponse.java @@ -0,0 +1,23 @@ +package com.jaspersoft.android.sdk.client.oxm.report; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class ReportDataResponse { + private final boolean isFinal; + private final String data; + + public ReportDataResponse(boolean isFinal, String data) { + this.isFinal = isFinal; + this.data = data; + } + + public boolean isFinal() { + return isFinal; + } + + public String getData() { + return data; + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionRequest.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionRequest.java index 5694ec2f..600d31ed 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionRequest.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionRequest.java @@ -24,137 +24,13 @@ package com.jaspersoft.android.sdk.client.oxm.report; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Root; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.List; - /** * @author Ivan Gadzhega * @since 1.8 */ @Root -public class ReportExecutionRequest { - - @Element - private String reportUnitUri; - - @Element(required=false) - private boolean async; - - @Element(required=false) - private boolean freshData; - - @Element(required=false) - private boolean saveDataSnapshot; - - @Element - private String outputFormat; - - @Element(required=false) - private boolean interactive; - - @Element(required=false) - private boolean ignorePagination; - - @Element(required=false) - private String pages; - - @Element(required=false) - private String attachmentsPrefix; - - @ElementList(required=false) - private List parameters; - - - public void setAttachmentsPrefix(String attachmentsPrefix) { - try { - this.attachmentsPrefix = URLEncoder.encode(attachmentsPrefix, "UTF-8"); - } catch (UnsupportedEncodingException exception) { - this.attachmentsPrefix = attachmentsPrefix; - } catch (NullPointerException exception) { - this.attachmentsPrefix = attachmentsPrefix; - } - } - - public String getAttachmentsPrefix() { - return attachmentsPrefix; - } - - public String getReportUnitUri() { - return reportUnitUri; - } - - public void setReportUnitUri(String reportUnitUri) { - this.reportUnitUri = reportUnitUri; - } - - public boolean isAsync() { - return async; - } - - public void setAsync(boolean async) { - this.async = async; - } - - public boolean isFreshData() { - return freshData; - } - - public void setFreshData(boolean freshData) { - this.freshData = freshData; - } - - public boolean isSaveDataSnapshot() { - return saveDataSnapshot; - } - - public void setSaveDataSnapshot(boolean saveDataSnapshot) { - this.saveDataSnapshot = saveDataSnapshot; - } - - public String getOutputFormat() { - return outputFormat; - } - - public void setOutputFormat(String outputFormat) { - this.outputFormat = outputFormat; - } - - public boolean isInteractive() { - return interactive; - } - - public void setInteractive(boolean interactive) { - this.interactive = interactive; - } - - public boolean isIgnorePagination() { - return ignorePagination; - } - - public void setIgnorePagination(boolean ignorePagination) { - this.ignorePagination = ignorePagination; - } - - public String getPages() { - return pages; - } - - public void setPages(String pages) { - this.pages = pages; - } - - public List getParameters() { - return parameters; - } - - public void setParameters(List parameters) { - this.parameters = parameters; - } - +public class ReportExecutionRequest extends ExecutionRequest { } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionResponse.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionResponse.java index 594d4feb..1e1ff44b 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionResponse.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportExecutionResponse.java @@ -106,4 +106,7 @@ public void setTotalPages(int totalPages) { this.totalPages = totalPages; } + public ReportStatus getReportStatus() { + return ReportStatus.valueOf(status.toUpperCase()); + } } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportParameter.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportParameter.java index 8d80e9d1..ef16b0a3 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportParameter.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportParameter.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; + import org.simpleframework.xml.Attribute; import org.simpleframework.xml.ElementList; diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportStatus.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportStatus.java new file mode 100644 index 00000000..317d8385 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportStatus.java @@ -0,0 +1,9 @@ +package com.jaspersoft.android.sdk.client.oxm.report; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public enum ReportStatus { + QUEUED, READY, FAILED, EXECUTION +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportStatusResponse.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportStatusResponse.java new file mode 100644 index 00000000..33b7ed1d --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/report/ReportStatusResponse.java @@ -0,0 +1,43 @@ +package com.jaspersoft.android.sdk.client.oxm.report; + +import com.jaspersoft.android.sdk.client.oxm.converter.ReportStatusConverter; + +import org.simpleframework.xml.Element; +import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; + +/** + * @author Tom Koptel + * @since 1.9 + */ +@Root(name = "status") +@Convert(ReportStatusConverter.class) +public class ReportStatusResponse { + + @Element(required = false) + private String mStatus; + + /** + * Otherwise, the framework cannot instantiate the class for deserialization. + * + * http://stackoverflow.com/questions/7470992/exception-with-simple-xml-framework-deserialization + */ + public ReportStatusResponse() { + } + + public ReportStatusResponse(String status) { + mStatus = status; + } + + public ReportStatus getReportStatus() { + return ReportStatus.valueOf(mStatus.toUpperCase()); + } + + public String getStatus() { + return mStatus; + } + + public void setStatus(String status) { + this.mStatus = status; + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookup.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookup.java index f7a6e39b..196a0d8e 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookup.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Jaspersoft Corporation. All rights reserved. + * Copyright (C) 2012-2014 Jaspersoft Corporation. All rights reserved. * http://community.jaspersoft.com/project/mobile-sdk-android * * Unless you have purchased a commercial license agreement from Jaspersoft, @@ -24,6 +24,9 @@ package com.jaspersoft.android.sdk.client.oxm.resource; +import android.os.Parcel; +import android.os.Parcelable; + import org.simpleframework.xml.Element; /** @@ -32,25 +35,69 @@ * @author Ivan Gadzhega * @since 1.7 */ -public class ResourceLookup { +public class ResourceLookup implements Parcelable { @Element(required=false) - private String label; + protected String label; @Element(required=false) - private String description; - @Element - private String uri; + protected String description; @Element - private String resourceType; + protected String uri; + @Element(required=false) + protected String resourceType; @Element(required=false) - private Integer version; + protected int version; @Element(required=false) - private Integer permissionMask; + protected int permissionMask; @Element(required=false) - private String creationDate; + protected String creationDate; @Element(required=false) - private String updateDate; + protected String updateDate; + + public ResourceLookup() { } + + //--------------------------------------------------------------------- + // Parcelable + //--------------------------------------------------------------------- + + public ResourceLookup(Parcel source) { + this.label = source.readString(); + this.description = source.readString(); + this.uri = source.readString(); + this.resourceType = source.readString(); + this.creationDate = source.readString(); + this.updateDate = source.readString(); + this.version = source.readInt(); + this.permissionMask = source.readInt(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public ResourceLookup createFromParcel(Parcel source) { + return new ResourceLookup(source); + } + + public ResourceLookup[] newArray(int size) { + return new ResourceLookup[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(label); + dest.writeString(description); + dest.writeString(uri); + dest.writeString(resourceType); + dest.writeString(creationDate); + dest.writeString(updateDate); + dest.writeInt(version); + dest.writeInt(permissionMask); + } //--------------------------------------------------------------------- // Getters & Setters @@ -96,19 +143,19 @@ public void setUri(String uri) { this.uri = uri; } - public Integer getVersion() { + public int getVersion() { return version; } - public void setVersion(Integer version) { + public void setVersion(int version) { this.version = version; } - public Integer getPermissionMask() { + public int getPermissionMask() { return permissionMask; } - public void setPermissionMask(Integer permissionMask) { + public void setPermissionMask(int permissionMask) { this.permissionMask = permissionMask; } @@ -136,6 +183,7 @@ public enum ResourceType { folder, reportUnit, dashboard, + legacyDashboard, unknown } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookupSearchCriteria.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookupSearchCriteria.java new file mode 100644 index 00000000..7fc52460 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookupSearchCriteria.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2012-2014 Jaspersoft Corporation. All rights reserved. + * http://www.jaspersoft.com. + * + * Unless you have purchased a commercial license agreement from Jaspersoft, + * the following license terms apply: + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.jaspersoft.android.sdk.client.oxm.resource; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Ivan Gadzhega + * @since 2.0 + */ +public class ResourceLookupSearchCriteria implements Parcelable { + + private String folderUri; + private String query; + private List types; + private String sortBy; + + private boolean recursive = true; + private boolean forceFullPage; + private int offset = 0; + private int limit = 100; + + public ResourceLookupSearchCriteria() { + } + + public ResourceLookupSearchCriteria(ResourceLookupSearchCriteria oldCriteria) { + this.folderUri = oldCriteria.getFolderUri(); + this.query = oldCriteria.getQuery(); + this.types = new ArrayList(oldCriteria.getTypes()); + this.sortBy = oldCriteria.getSortBy(); + this.recursive = oldCriteria.isRecursive(); + this.forceFullPage = oldCriteria.isForceFullPage(); + this.offset = oldCriteria.getOffset(); + this.limit = oldCriteria.getLimit(); + } + + //--------------------------------------------------------------------- + // Parcelable + //--------------------------------------------------------------------- + + public ResourceLookupSearchCriteria(Parcel source) { + this.folderUri = source.readString(); + this.query = source.readString(); + this.types = source.createStringArrayList(); + this.sortBy = source.readString(); + this.recursive = source.readByte() != 0; + this.forceFullPage = source.readByte() != 0; + this.offset = source.readInt(); + this.limit = source.readInt(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public ResourceLookupSearchCriteria createFromParcel(Parcel source) { + return new ResourceLookupSearchCriteria(source); + } + + public ResourceLookupSearchCriteria[] newArray(int size) { + return new ResourceLookupSearchCriteria[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(folderUri); + dest.writeString(query); + dest.writeStringList(types); + dest.writeString(sortBy); + dest.writeByte((byte) (recursive ? 1 : 0)); + dest.writeByte((byte) (forceFullPage ? 1 : 0)); + dest.writeInt(offset); + dest.writeInt(limit); + } + + //--------------------------------------------------------------------- + // Getters & Setters + //--------------------------------------------------------------------- + + /** + * {@link ResourceLookupSearchCriteria#setFolderUri} + */ + public String getFolderUri() { + return folderUri; + } + + /** + * The path of the base folder for the search. + */ + public void setFolderUri(String folderUri) { + this.folderUri = folderUri; + } + + /** + * {@link ResourceLookupSearchCriteria#setQuery} + */ + public String getQuery() { + return query; + } + + /** + * Search for resources having the specified text in the name or description. + * Note that the search string does not match in the ID of resources. + */ + public void setQuery(String query) { + this.query = query; + } + + /** + * {@link ResourceLookupSearchCriteria#setTypes} + */ + public List getTypes() { + return types; + } + + /** + * Match only resources of the given type. Multiple type parameters are allowed. + * Wrong values are ignored. + */ + public void setTypes(List types) { + this.types = types; + } + + /** + * {@link ResourceLookupSearchCriteria#setSortBy} + */ + public String getSortBy() { + return sortBy; + } + + /** + * One of the following strings representing a field in the results to sort by: uri, + * label, description, type, creationDate, updateDate, accessTime, or popularity + * (based on access events). + */ + public void setSortBy(String sortBy) { + this.sortBy = sortBy; + } + + /** + * {@link ResourceLookupSearchCriteria#setRecursive} + */ + public boolean isRecursive() { + return recursive; + } + + /** + * Indicates whether search should include all sub-folders recursively. When + * omitted, the default behavior is recursive (true). + */ + public void setRecursive(boolean recursive) { + this.recursive = recursive; + } + + /** + * {@link ResourceLookupSearchCriteria#setOffset} + */ + public int getOffset() { + return offset; + } + + /** + * Used for pagination to request an offset in the set of results. This is + * equivalent to a specific page number. The default offset is 1 (first page). + */ + public void setOffset(int offset) { + this.offset = offset; + } + + /** + * {@link ResourceLookupSearchCriteria#setLimit} + */ + public int getLimit() { + return limit; + } + + /** + * Used for pagination to specify the maximum number of resources to return in + * each response. This is equivalent to the number of results per page. The + * default limit is 100. + */ + public void setLimit(int limit) { + this.limit = limit; + } + + /** + * {@link ResourceLookupSearchCriteria#setForceFullPage} + */ + public boolean isForceFullPage() { + return forceFullPage; + } + + /** + * With forceFullPage=false, + * This is the offset to request the next page. The Next-Offset is equivalent to Start-Index+limit, except on the last page. + * On the the last page, the Next-Offset is omitted to indicate there are no further pages. + * {@link ResourceLookupSearchCriteria#setLimit} + */ + + /** + * With forceFullPage=false we receive different pagination experience. Considering header + * for response Next-Offset which is the offset to request the next page. The Next-Offset + * is equivalent to Start-Index+limit, except on the last page. + * On the the last page, the Next-Offset is omitted to indicate there are no further pages. + *
+ *
+ * With forceFullPage=true enables full page pagination. Depending on the type of search and + * user permissions, this parameter can cause significant performance delays. + * + * @param forceFullPage accepts boolean value + */ + public void setForceFullPage(boolean forceFullPage) { + this.forceFullPage = forceFullPage; + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookupsList.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookupsList.java index 36dd817a..688462e9 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookupsList.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/resource/ResourceLookupsList.java @@ -35,6 +35,7 @@ @Root(name="resources") public class ResourceLookupsList { + public static int NO_OFFSET = -1; @ElementList(entry="resourceLookup", inline=true, required=false, empty=false) private List resourceLookups; @@ -45,6 +46,12 @@ public class ResourceLookupsList { @Element(required=false) private int totalCount; + @Element(required=false) + private int nextOffset; + + @Element(required=false) + private int startIndex; + public ResourceLookupsList() { this.resourceLookups = new ArrayList(); this.resultCount = 0; @@ -86,4 +93,28 @@ public void setTotalCount(int totalCount) { public void setTotalCount(String totalCount) { this.totalCount = (totalCount != null) ? Integer.parseInt(totalCount) : 0; } + + public int getStartIndex() { + return startIndex; + } + + public void setStartIndex(String startIndex) { + this.startIndex = (startIndex != null) ? Integer.parseInt(startIndex) : 0; + } + + public void setStartIndex(int startIndex) { + this.startIndex = startIndex; + } + + public int getNextOffset() { + return nextOffset; + } + + public void setNextOffset(String nextOffset) { + this.nextOffset = (nextOffset != null) ? Integer.parseInt(nextOffset) : NO_OFFSET; + } + + public void setNextOffset(int nextOffset) { + this.nextOffset = nextOffset; + } } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/server/ServerInfo.java b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/server/ServerInfo.java index c95ab5dd..a5bef84a 100644 --- a/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/server/ServerInfo.java +++ b/client/src/main/java/com/jaspersoft/android/sdk/client/oxm/server/ServerInfo.java @@ -24,6 +24,8 @@ import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; +import java.math.BigDecimal; + /** * @author Ivan Gadzhega * @since 1.4 @@ -33,9 +35,11 @@ public class ServerInfo { public static class VERSION_CODES { public static final int UNKNOWN = 0; - public static final int EMERALD = 50000; - public static final int EMERALD_MR1 = 50200; - public static final int EMERALD_TWO = 50500; + public static final double EMERALD = 5.0; + public static final double EMERALD_MR1 = 5.2; + public static final double EMERALD_TWO = 5.5; + public static final double EMERALD_THREE = 5.6; + public static final double AMBER = 6.0; } public static class EDITIONS { @@ -63,7 +67,7 @@ public static class EDITIONS { private String version; - private int versionCode; + private double versionCode; public ServerInfo() { @@ -78,18 +82,21 @@ public void setVersion(String version) { // update version code if (version != null) { String[] subs = version.split("\\."); - for (int i = 0; i < subs.length; i++) { - int exponent = ((subs.length - 1) - i) * 2; - int subVersion; + BigDecimal decimalSubVersion, decimalFactor, decimalResult; + BigDecimal decimalVersion = new BigDecimal("0"); + for (int i = 0; i < subs.length; i++) { try { - subVersion = Integer.parseInt(subs[i]); + decimalSubVersion = new BigDecimal(Integer.parseInt(subs[i])); } catch (NumberFormatException ex) { - subVersion = 0; + decimalSubVersion = new BigDecimal("0"); } - versionCode += subVersion * Math.pow(10, exponent); + decimalFactor = new BigDecimal(String.valueOf(Math.pow(10, i * -1))); + decimalResult = decimalSubVersion.multiply(decimalFactor); + decimalVersion = decimalVersion.add(decimalResult); } + versionCode = decimalVersion.doubleValue(); } } @@ -150,11 +157,11 @@ public void setLicenseType(String licenseType) { this.licenseType = licenseType; } - public int getVersionCode() { + public double getVersionCode() { return versionCode; } - public void setVersionCode(int versionCode) { + public void setVersionCode(double versionCode) { this.versionCode = versionCode; } diff --git a/client/src/main/java/com/jaspersoft/android/sdk/util/CookieHttpRequestInterceptor.java b/client/src/main/java/com/jaspersoft/android/sdk/util/CookieHttpRequestInterceptor.java new file mode 100644 index 00000000..db2b449c --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/util/CookieHttpRequestInterceptor.java @@ -0,0 +1,67 @@ +package com.jaspersoft.android.sdk.util; + +import android.util.Base64; +import android.util.Log; + +import com.jaspersoft.android.sdk.client.JsServerProfile; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; + +import java.io.IOException; +import java.util.List; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class CookieHttpRequestInterceptor implements ClientHttpRequestInterceptor { + private static final String SET_COOKIE = "set-cookie"; + private static final String COOKIE = "Cookie"; + private static final String COOKIE_STORE = "cookieStore"; + private final JsServerProfile jsServerProfile; + + public CookieHttpRequestInterceptor(JsServerProfile jsServerProfile) { + this.jsServerProfile = jsServerProfile; + } + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] byteArray, + ClientHttpRequestExecution execution) throws IOException { + + Log.d(getClass().getSimpleName(), ">>> entering intercept"); + List cookies = request.getHeaders().get(COOKIE); + // if the header doesn't exist, add any existing, saved cookies + if (cookies == null) { + List cookieStore = (List) StaticCacheHelper.retrieveObjectFromCache(COOKIE_STORE); + // if we have stored cookies, add them to the headers + if (cookieStore != null) { + request.getHeaders().add(COOKIE, StringUtils.join(cookieStore, ";")); + } else { + Log.d(getClass().getSimpleName(), "Setting basic auth"); + // Basic Authentication + String authorisation = jsServerProfile.getUsernameWithOrgId() + ":" + jsServerProfile.getPassword(); + byte[] encodedAuthorisation = Base64.encode(authorisation.getBytes(), Base64.NO_WRAP); + request.getHeaders().set("Authorization", "Basic " + new String(encodedAuthorisation)); + // disable buggy keep-alive + request.getHeaders().set("Connection", "close"); + } + } + + // execute the request + ClientHttpResponse response = execution.execute(request, byteArray); + // pull any cookies off and store them + cookies = response.getHeaders().get(SET_COOKIE); + if (cookies != null) { + for (String cookie : cookies) { + Log.d(getClass().getSimpleName(), ">>> response cookie = " + cookie); + } + StaticCacheHelper.storeObjectInCache(COOKIE_STORE, cookies); + } + Log.d(getClass().getSimpleName(), ">>> leaving intercept"); + return response; + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/util/KeepAliveHttpRequestInterceptor.java b/client/src/main/java/com/jaspersoft/android/sdk/util/KeepAliveHttpRequestInterceptor.java new file mode 100644 index 00000000..0586ce00 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/util/KeepAliveHttpRequestInterceptor.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.jaspersoft.android.sdk.util; + +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; + +import java.io.IOException; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class KeepAliveHttpRequestInterceptor implements ClientHttpRequestInterceptor { + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + request.getHeaders().add("Connection", "Close"); + return execution.execute(request, body); + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/util/LocalesHttpRequestInterceptor.java b/client/src/main/java/com/jaspersoft/android/sdk/util/LocalesHttpRequestInterceptor.java new file mode 100644 index 00000000..275aea1a --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/util/LocalesHttpRequestInterceptor.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.jaspersoft.android.sdk.util; + +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; + +import java.io.IOException; +import java.util.Locale; +import java.util.TimeZone; + +public class LocalesHttpRequestInterceptor implements ClientHttpRequestInterceptor { + private static final String ACCEPT_TIMEZONE = "Accept-Timezone"; + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + String timeZone = createGmtOffsetString(true, true, TimeZone.getDefault().getRawOffset()); + // Because of HTTP accepts this type separator '-' we replace default one + String locale = Locale.getDefault().toString().replaceAll("_", "-"); + + request.getHeaders().setAcceptLanguage(locale); + request.getHeaders().add(ACCEPT_TIMEZONE, timeZone); + + return execution.execute(request, body); + } + + private String createGmtOffsetString(boolean includeGmt, + boolean includeMinuteSeparator, int offsetMillis) { + int offsetMinutes = offsetMillis / 60000; + char sign = '+'; + if (offsetMinutes < 0) { + sign = '-'; + offsetMinutes = -offsetMinutes; + } + StringBuilder builder = new StringBuilder(9); + if (includeGmt) { + builder.append("GMT"); + } + builder.append(sign); + appendNumber(builder, 2, offsetMinutes / 60); + if (includeMinuteSeparator) { + builder.append(':'); + } + appendNumber(builder, 2, offsetMinutes % 60); + return builder.toString(); + } + + private void appendNumber(StringBuilder builder, int count, int value) { + String string = Integer.toString(value); + for (int i = 0; i < count - string.length(); i++) { + builder.append('0'); + } + builder.append(string); + } +} diff --git a/client/src/main/java/com/jaspersoft/android/sdk/util/StaticCacheHelper.java b/client/src/main/java/com/jaspersoft/android/sdk/util/StaticCacheHelper.java new file mode 100644 index 00000000..a1e495c8 --- /dev/null +++ b/client/src/main/java/com/jaspersoft/android/sdk/util/StaticCacheHelper.java @@ -0,0 +1,117 @@ +package com.jaspersoft.android.sdk.util; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * @author Tom Koptel + * @since 1.9 + */ +public class StaticCacheHelper { + + private static final long TIME_TO_LIVE = TimeUnit.MINUTES.toMillis(20); + + private static final Map cacheMap = new HashMap(); + + /** + * Retrieves an item from the cache. If found, the method compares + * the object's expiration date to the current time and only returns + * the object if the expiration date has not passed. + * + * @param cacheKey + * @return + */ + public static Object retrieveObjectFromCache(String cacheKey) { + Element e = cacheMap.get(cacheKey); + Object o = null; + if (e != null) { + Date now = new Date(); + if (e.getExpirationDate().after(now)) { + o = e.getObject(); + } else { + removeCacheItem(cacheKey); + } + } + return o; + } + + /** + * Stores an object in the cache, wrapped by an Element object. + * The Element object has an expiration date, which will be set to + * now + this class' TIME_TO_LIVE setting. + * + * @param cacheKey + * @param object + */ + public static void storeObjectInCache(String cacheKey, Object object) { + Date expirationDate = new Date(System.currentTimeMillis() + TIME_TO_LIVE); + Element e = new Element(object, expirationDate); + cacheMap.put(cacheKey, e); + } + + /** + * Stores an object in the cache, wrapped by an Element object. + * The Element object has an expiration date, which will be set to + * now + the timeToLiveInMilliseconds value that is passed into the method. + * + * @param cacheKey + * @param object + * @param timeToLiveInMilliseconds + */ + public static void storeObjectInCache(String cacheKey, Object object, int timeToLiveInMilliseconds) { + Date expirationDate = new Date(System.currentTimeMillis() + timeToLiveInMilliseconds); + Element e = new Element(object, expirationDate); + cacheMap.put(cacheKey, e); + } + + public static void removeCacheItem(String cacheKey) { + cacheMap.remove(cacheKey); + } + + public static void clearCache() { + cacheMap.clear(); + } + + static class Element { + + private Object object; + private Date expirationDate; + + /** + * @param object + * @param key + * @param expirationDate + */ + private Element(Object object, Date expirationDate) { + super(); + this.object = object; + this.expirationDate = expirationDate; + } + /** + * @return the object + */ + public Object getObject() { + return object; + } + /** + * @param object the object to set + */ + public void setObject(Object object) { + this.object = object; + } + /** + * @return the expirationDate + */ + public Date getExpirationDate() { + return expirationDate; + } + /** + * @param expirationDate the expirationDate to set + */ + public void setExpirationDate(Date expirationDate) { + this.expirationDate = expirationDate; + } + } +} \ No newline at end of file diff --git a/client/src/test/java/InputControlWrapperTest.java b/client/src/test/java/InputControlWrapperTest.java deleted file mode 100644 index 36382430..00000000 --- a/client/src/test/java/InputControlWrapperTest.java +++ /dev/null @@ -1,231 +0,0 @@ -import com.jaspersoft.android.sdk.client.ic.InputControlWrapper; -import com.jaspersoft.android.sdk.client.oxm.ResourceDescriptor; -import com.jaspersoft.android.sdk.client.oxm.ResourceProperty; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.mockito.Mockito.*; -import static junit.framework.Assert.*; - -/** - * @author Ivan Gadzhega - * @version $Id$ - * @since 1.0 - */ -public class InputControlWrapperTest { - - private final static String label = "Input Control"; - private final static String name = "inputControl"; - private final static String uriString = "/Samples/AllAccounts/inputControl"; - - private ResourceDescriptor resourceDescriptor; - - - @Before - public void initResourceDescriptor() { - resourceDescriptor = mock(ResourceDescriptor.class); - when(resourceDescriptor.getLabel()).thenReturn(label); - when(resourceDescriptor.getName()).thenReturn(name); - when(resourceDescriptor.getUriString()).thenReturn(uriString); - } - - @Test - public void test_init() { - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - assertEquals(label, wrapper.getLabel()); - assertEquals(name, wrapper.getName()); - assertEquals(uriString, wrapper.getUri()); - } - - @Test - public void test_init_type() { - ResourceProperty typeProperty = mock(ResourceProperty.class); - when(typeProperty.getName()).thenReturn(ResourceDescriptor.PROP_INPUTCONTROL_TYPE); - when(typeProperty.getValue()).thenReturn(Byte.toString(ResourceDescriptor.IC_TYPE_BOOLEAN)); - - List propertyList = new ArrayList(); - propertyList.add(typeProperty); - - when(resourceDescriptor.getProperties()).thenReturn(propertyList); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertEquals(ResourceDescriptor.IC_TYPE_BOOLEAN, wrapper.getType()); - } - - @Test - public void test_init_isMandatory() { - ResourceProperty typeProperty = mock(ResourceProperty.class); - when(typeProperty.getName()).thenReturn(ResourceDescriptor.PROP_INPUTCONTROL_IS_MANDATORY); - when(typeProperty.getValue()).thenReturn("true"); - - List propertyList = new ArrayList(); - propertyList.add(typeProperty); - - when(resourceDescriptor.getProperties()).thenReturn(propertyList); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertEquals(true, wrapper.isMandatory()); - } - - @Test - public void test_init_isReadOnly() { - ResourceProperty typeProperty = mock(ResourceProperty.class); - when(typeProperty.getName()).thenReturn(ResourceDescriptor.PROP_INPUTCONTROL_IS_READONLY); - when(typeProperty.getValue()).thenReturn("true"); - - List propertyList = new ArrayList(); - propertyList.add(typeProperty); - - when(resourceDescriptor.getProperties()).thenReturn(propertyList); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertEquals(true, wrapper.isReadOnly()); - } - - @Test - public void test_init_isVisible() { - ResourceProperty typeProperty = mock(ResourceProperty.class); - when(typeProperty.getName()).thenReturn(ResourceDescriptor.PROP_INPUTCONTROL_IS_VISIBLE); - when(typeProperty.getValue()).thenReturn("true"); - - List propertyList = new ArrayList(); - propertyList.add(typeProperty); - - when(resourceDescriptor.getProperties()).thenReturn(propertyList); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertEquals(true, wrapper.isVisible()); - } - - @Test - public void test_init_query() { - String query = "query"; - String dataSourceUri = "dataSourceUri"; - - ResourceProperty queryProperty = mock(ResourceProperty.class); - when(queryProperty.getValue()).thenReturn(query); - - ResourceDescriptor internalResource = mock(ResourceDescriptor.class); - when(internalResource.getWsType()).thenReturn(ResourceDescriptor.WsType.query); - when(internalResource.getDataSourceUri()).thenReturn(dataSourceUri); - when(internalResource.getPropertyByName(ResourceDescriptor.PROP_QUERY)).thenReturn(queryProperty); - - List internalResources = new ArrayList(); - internalResources.add(internalResource); - - when(resourceDescriptor.getInternalResources()).thenReturn(internalResources); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertEquals(query, wrapper.getQuery()); - assertEquals(dataSourceUri, wrapper.getDataSourceUri()); - } - - @Test - public void test_init_singleValue_dataType() { - ResourceProperty typeProperty = mock(ResourceProperty.class); - when(typeProperty.getName()).thenReturn(ResourceDescriptor.PROP_INPUTCONTROL_TYPE); - when(typeProperty.getValue()).thenReturn(Byte.toString(ResourceDescriptor.IC_TYPE_SINGLE_VALUE)); - - List propertyList = new ArrayList(); - propertyList.add(typeProperty); - - when(resourceDescriptor.getProperties()).thenReturn(propertyList); - - Byte dataTypeValue = ResourceDescriptor.DT_TYPE_TEXT; - - ResourceProperty dataTypeProperty = mock(ResourceProperty.class); - when(dataTypeProperty.getValue()).thenReturn(dataTypeValue.toString()); - - ResourceDescriptor internalResource = mock(ResourceDescriptor.class); - when(internalResource.getWsType()).thenReturn(ResourceDescriptor.WsType.dataType); - when(internalResource.getPropertyByName(ResourceDescriptor.PROP_DATATYPE_TYPE)).thenReturn(dataTypeProperty); - - List internalResources = new ArrayList(); - internalResources.add(internalResource); - - when(resourceDescriptor.getInternalResources()).thenReturn(internalResources); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertEquals(dataTypeValue.byteValue(), wrapper.getDataType()); - } - - @Test - public void test_init_parameterDependencies() { - Map queries = new HashMap(); - queries.put( - "Standart Parameter", - "select distinct billing_address_state, billing_address_country from accounts where " - + "billing_address_country = $P{Country_multi_select} order by billing_address_country, billing_address_state" - ); - queries.put( - "Include Parameter", - "select distinct billing_address_state, billing_address_country from accounts where " - + "billing_address_country = $P!{Country_multi_select} order by billing_address_country, billing_address_state" - ); - queries.put( - "Dynamic Parameter", - "select distinct billing_address_state, billing_address_country from accounts where " - + "$X{IN, billing_address_country, Country_multi_select} order by billing_address_country, billing_address_state" - ); - - for (Map.Entry query : queries.entrySet()) { - ResourceProperty queryProperty = mock(ResourceProperty.class); - when(queryProperty.getValue()).thenReturn(query.getValue()); - - ResourceDescriptor internalResource = mock(ResourceDescriptor.class); - when(internalResource.getWsType()).thenReturn(ResourceDescriptor.WsType.query); - when(internalResource.getPropertyByName(ResourceDescriptor.PROP_QUERY)).thenReturn(queryProperty); - - List internalResources = new ArrayList(); - internalResources.add(internalResource); - - when(resourceDescriptor.getInternalResources()).thenReturn(internalResources); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertFalse(query.getKey(), wrapper.getParameterDependencies().isEmpty()); - } - } - - - @Test - public void test_init_valuesList() { - List listOfValues = (List) mock(List.class); - - ResourceProperty lovProperty = mock(ResourceProperty.class); - when(lovProperty.getProperties()).thenReturn(listOfValues); - - ResourceDescriptor internalResource = mock(ResourceDescriptor.class); - when(internalResource.getWsType()).thenReturn(ResourceDescriptor.WsType.lov); - when(internalResource.getPropertyByName(ResourceDescriptor.PROP_LOV)).thenReturn(lovProperty);; - - List internalResources = new ArrayList(); - internalResources.add(internalResource); - - ResourceProperty typeProperty = mock(ResourceProperty.class); - when(typeProperty.getName()).thenReturn(ResourceDescriptor.PROP_INPUTCONTROL_TYPE); - when(typeProperty.getValue()).thenReturn(Byte.toString(ResourceDescriptor.IC_TYPE_SINGLE_SELECT_LIST_OF_VALUES)); - - List propertyList = new ArrayList(); - propertyList.add(typeProperty); - - when(resourceDescriptor.getInternalResources()).thenReturn(internalResources); - when(resourceDescriptor.getProperties()).thenReturn(propertyList); - - InputControlWrapper wrapper = new InputControlWrapper(resourceDescriptor); - - assertEquals(listOfValues, wrapper.getListOfValues()); - } - -} diff --git a/client/src/test/java/JsRestClientTest.java b/client/src/test/java/JsRestClientTest.java deleted file mode 100644 index c2a72993..00000000 --- a/client/src/test/java/JsRestClientTest.java +++ /dev/null @@ -1,269 +0,0 @@ -import com.jaspersoft.android.sdk.client.JsRestClient; -import com.jaspersoft.android.sdk.client.oxm.*; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpRequest; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.web.client.ResourceAccessException; -import org.springframework.web.client.ResponseErrorHandler; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriTemplate; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static org.mockito.Mockito.*; - -/** - * @author Ivan Gadzhega - * @version $Id$ - * @since 1.0 - */ -public class JsRestClientTest { - - @Mock - private RestTemplate restTemplate; - - @InjectMocks - private JsRestClient jsRestClient = new JsRestClient() { - @Override - protected int copyResponseToFile(ClientHttpResponse response, File file) { - // do nothing - return 0; - } - }; - - private final static String resourceUri = "/Samples/AllAccounts"; - private final static String folderUri = "/reports/samples"; - private final static String inputControlUri = "/Samples/AllAccounts/inputControl"; - private final static String datasourceUri = "/datasource"; - private final String uuid = "d7bf6c9-9077-41f7-a2d4-8682e74b637e"; - private final static String attachmentName = "img_0_0_0"; - - @Before - public void initMocks() { - MockitoAnnotations.initMocks(this); - } - - //--------------------------------------------------------------------- - // The Resource Service - //--------------------------------------------------------------------- - - @Test - public void test_getResource() { - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_RESOURCE_URI + resourceUri; - - ResourceDescriptor expectedDescriptor = mock(ResourceDescriptor.class); - when(restTemplate.getForObject(fullUri, ResourceDescriptor.class)).thenReturn(expectedDescriptor); - - ResourceDescriptor actualDescriptor = jsRestClient.getResource(resourceUri); - - verify(restTemplate).getForObject(fullUri, ResourceDescriptor.class); - assertEquals(expectedDescriptor, actualDescriptor); - } - - @Test - public void test_modifyResource() { - ResourceDescriptor resourceDescriptor = mock(ResourceDescriptor.class); - - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_RESOURCE_URI + resourceDescriptor.getUriString(); - - jsRestClient.modifyResource(resourceDescriptor); - verify(restTemplate).postForLocation(fullUri, resourceDescriptor); - } - - @Test - public void test_deleteResource() { - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_RESOURCE_URI + resourceUri; - - jsRestClient.deleteResource(resourceUri); - verify(restTemplate).delete(fullUri); - } - - //--------------------------------------------------------------------- - // The Resources Service - //--------------------------------------------------------------------- - - @Test - public void test_getResourcesList() { - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_RESOURCES_URI + folderUri; - - List expectedResourcesList = (List) mock(List.class); - - ResourcesList resourcesList = mock(ResourcesList.class); - when(resourcesList.getResourceDescriptors()).thenReturn(expectedResourcesList); - - when(restTemplate.getForObject(fullUri, ResourcesList.class)).thenReturn(resourcesList); - - List actualResourcesList = jsRestClient.getResourcesList(folderUri); - - verify(restTemplate).getForObject(fullUri, ResourcesList.class); - assertEquals(expectedResourcesList, actualResourcesList); - } - - @Test - public void test_getResourcesList_matchingParameters() { - String query = "AllAccounts"; - String type = "reportUnit"; - Boolean recursive = true; - Integer limit = 10; - - String uriVariablesTemplate = "?q={query}&type={type}&recursive={recursive}&limit={limit}"; - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_RESOURCES_URI + folderUri + uriVariablesTemplate; - - List expectedResourcesList = (List) mock(List.class); - - ResourcesList resourcesList = mock(ResourcesList.class); - when(resourcesList.getResourceDescriptors()).thenReturn(expectedResourcesList); - - when(restTemplate.getForObject(fullUri, ResourcesList.class, query, type, recursive, limit)) - .thenReturn(resourcesList); - - List actualResourcesList = jsRestClient.getResourcesList(folderUri, query, type, recursive, limit); - - verify(restTemplate).getForObject(fullUri, ResourcesList.class, query, type, recursive, limit); - assertEquals(expectedResourcesList, actualResourcesList); - } - - //--------------------------------------------------------------------- - // The Report Service - //--------------------------------------------------------------------- - - @Test - public void test_getReportDescriptor() { - String format = "HTML"; - ResourceDescriptor resourceDescriptor = mock(ResourceDescriptor.class); - - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_REPORT_URI + - resourceDescriptor.getUriString() + "?IMAGES_URI=./&RUN_OUTPUT_FORMAT={format}"; - - ReportDescriptor expectedDescriptor = mock(ReportDescriptor.class); - - ResponseEntity responseEntity = (ResponseEntity) mock(ResponseEntity.class); - - when(responseEntity.getBody()).thenReturn(expectedDescriptor); - - when(restTemplate.exchange(eq(fullUri), eq(HttpMethod.PUT), isA(HttpEntity.class), eq(ReportDescriptor.class), eq(format))) - .thenReturn(responseEntity); - - ReportDescriptor actualDescriptor = jsRestClient.getReportDescriptor(resourceDescriptor, format); - - verify(restTemplate).exchange(eq(fullUri), eq(HttpMethod.PUT), isA(HttpEntity.class), eq(ReportDescriptor.class), eq(format)); - assertEquals(expectedDescriptor, actualDescriptor); - } - - @Test - public void test_getReportAttachment() { - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_REPORT_URI + "/{uuid}?file={name}"; - - byte[] expectedAttachment = new byte[10]; - - ResponseEntity responseEntity = (ResponseEntity) mock(ResponseEntity.class); - when(responseEntity.getBody()).thenReturn(expectedAttachment); - - when(restTemplate.exchange(eq(fullUri), eq(HttpMethod.GET), isA(HttpEntity.class), eq(byte[].class), eq(uuid), eq(attachmentName))) - .thenReturn(responseEntity); - - byte[] actualAttachment = jsRestClient.getReportAttachment(uuid, attachmentName); - - verify(restTemplate).exchange(eq(fullUri), eq(HttpMethod.GET), isA(HttpEntity.class), eq(byte[].class), eq(uuid), eq(attachmentName)); - assertEquals(expectedAttachment, actualAttachment); - } - - @Test - public void test_saveReportAttachmentToFile() { - String fullUri = jsRestClient.getRestServicesUrl() + JsRestClient.REST_REPORT_URI + "/{uuid}?file={name}"; - - ClientHttpRequestFactory factory = mock(ClientHttpRequestFactory.class); - when(restTemplate.getRequestFactory()).thenReturn(factory); - - ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); - when(restTemplate.getErrorHandler()).thenReturn(errorHandler); - - UriTemplate uriTemplate = new UriTemplate(fullUri); - URI expanded = uriTemplate.expand(uuid, attachmentName); - - ClientHttpRequest request = mock(ClientHttpRequest.class); - ClientHttpResponse response = mock(ClientHttpResponse.class); - - InputStream inputStream = mock(InputStream.class); - - File file = mock(File.class); - - try { - when(factory.createRequest(expanded, HttpMethod.GET)).thenReturn(request); - when(request.execute()).thenReturn(response); - - jsRestClient.saveReportAttachmentToFile(uuid, attachmentName, file); - verify(restTemplate).getRequestFactory(); - verify(factory).createRequest(expanded, HttpMethod.GET); - verify(response).close(); - } catch (IOException ex) { - throw new ResourceAccessException("I/O error: " + ex.getMessage(), ex); - } - } - - @Test - public void test_getInputControlWithQueryData() { - List params = new ArrayList(); - params.add(mock(ResourceParameter.class)); - params.add(mock(ResourceParameter.class)); - - StringBuilder fullUri = new StringBuilder(); - fullUri.append(jsRestClient.getRestServicesUrl()).append(JsRestClient.REST_RESOURCE_URI).append(inputControlUri); - fullUri.append("?IC_GET_QUERY_DATA=").append(datasourceUri); - - for(ResourceParameter parameter : params) { - fullUri.append(parameter.isListItem() ? "&PL_" : "&P_"); - fullUri.append(parameter.getName()).append("=").append(parameter.getValue()); - } - - ResourceDescriptor expectedDescriptor = mock(ResourceDescriptor.class); - when(restTemplate.getForObject(fullUri.toString(), ResourceDescriptor.class)).thenReturn(expectedDescriptor); - - ResourceDescriptor actualDescriptor = jsRestClient.getInputControlWithQueryData(inputControlUri, datasourceUri, params); - - verify(restTemplate).getForObject(fullUri.toString(), ResourceDescriptor.class); - assertEquals(expectedDescriptor, actualDescriptor); - } - - @Test - public void test_getInputControlQueryData() { - List params = new ArrayList(); - params.add(mock(ResourceParameter.class)); - params.add(mock(ResourceParameter.class)); - - - JsRestClient spyJsRestClient = spy(jsRestClient); - ResourceDescriptor resourceDescriptor = mock(ResourceDescriptor.class); - when(spyJsRestClient.getInputControlWithQueryData(inputControlUri, datasourceUri, params)).thenReturn(resourceDescriptor); - - ResourceProperty queryDataProperty = mock(ResourceProperty.class); - - List queryData = new ArrayList(); - queryData.add(mock(ResourceProperty.class)); - queryData.add(mock(ResourceProperty.class)); - - when(queryDataProperty.getProperties()).thenReturn(queryData); - - when(resourceDescriptor.getPropertyByName(ResourceDescriptor.PROP_QUERY_DATA)).thenReturn(queryDataProperty); - - List listOfValues = jsRestClient.getInputControlQueryData(inputControlUri, datasourceUri, params); - - verify(spyJsRestClient).getInputControlWithQueryData(inputControlUri, datasourceUri, params); - assertNotNull(listOfValues); - } -} diff --git a/client/src/test/java/JsServerProfileTest.java b/client/src/test/java/JsServerProfileTest.java deleted file mode 100644 index 7a63eeb3..00000000 --- a/client/src/test/java/JsServerProfileTest.java +++ /dev/null @@ -1,40 +0,0 @@ -import com.jaspersoft.android.sdk.client.JsServerProfile; -import org.junit.Test; - -import static junit.framework.Assert.*; - -/** - * @author Ivan Gadzhega - * @version $Id$ - * @since 1.0 - */ -public class JsServerProfileTest { - - private final static Long id = 1L; - private final static String alias = "Test Profile"; - private final static String serverUrl = "http://mobiledemo.jaspersoft.com/jasperserver-pro"; - private final static String organization = "organization"; - private final static String username = "user"; - private final static String password = "password"; - - @Test - public void test_getUsernameWithOrgId() { - JsServerProfile serverProfile = new JsServerProfile(id, alias, serverUrl, organization, username, password); - String actualResult = serverProfile.getUsernameWithOrgId(); - assertEquals(username + "|" + organization, actualResult); - } - - @Test - public void test_getUsernameWithOrgId_orgNull() { - JsServerProfile serverProfile = new JsServerProfile(id, alias, serverUrl, null, username, password); - String actualResult = serverProfile.getUsernameWithOrgId(); - assertEquals(username, actualResult); - } - - @Test - public void test_getUsernameWithOrgId_orgEmpty() { - JsServerProfile serverProfile = new JsServerProfile(id, alias, serverUrl, "", username, password); - String actualResult = serverProfile.getUsernameWithOrgId(); - assertEquals(username, actualResult); - } -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..7b359d71 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..e498f578 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Dec 12 15:16:42 PST 2012 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-2.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 582ec0ee..00000000 --- a/pom.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - 4.0.0 - - - UTF-8 - - - com.jaspersoft.android.sdk - js-android-sdk-aggregator - 1.8 - pom - - - client - ui - - - - - - com.google.android - android - 4.1.1.4 - provided - - - org.springframework.android - spring-android-rest-template - 1.0.1.RELEASE - - - com.octo.android.robospice - robospice - 1.4.11 - - - com.octo.android.robospice - robospice-spring-android - 1.4.11 - - - - org.simpleframework - simple-xml - 2.7 - - - - stax - stax - - - stax-api - stax - - - - xpp3 - xpp3 - - - - - - junit - junit - 4.9 - test - - - org.mockito - mockito-all - 1.9.0 - test - - - - - - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - 3.6.0 - true - - - 16 - - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - - - - \ No newline at end of file diff --git a/scripts/android-release-aar.gradle b/scripts/android-release-aar.gradle new file mode 100644 index 00000000..52c30fa7 --- /dev/null +++ b/scripts/android-release-aar.gradle @@ -0,0 +1,53 @@ +// ./gradlew clean build generateRelease +apply plugin: 'maven' + +def groupId = project.PUBLISH_GROUP_ID +def artifactId = project.PUBLISH_ARTIFACT_ID +def version = project.PUBLISH_VERSION + +def localReleaseDest = "${buildDir}/release/${version}" + +task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) +} + +task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { + classifier = 'javadoc' + from androidJavadocs.destinationDir +} + +task androidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +uploadArchives { + repositories.mavenDeployer { + pom.groupId = groupId + pom.artifactId = artifactId + pom.version = version + // Add other pom properties here if you want (developer details / licenses) + repository(url: "file://${localReleaseDest}") + } +} + +task zipRelease(type: Zip) { + from localReleaseDest + destinationDir buildDir + archiveName "release-${version}.zip" +} + +task generateRelease << { + println "Release ${version} can be found at ${localReleaseDest}/" + println "Release ${version} zipped can be found ${buildDir}/release-${version}.zip" +} + +generateRelease.dependsOn(uploadArchives) +generateRelease.dependsOn(zipRelease) + + +artifacts { + archives androidSourcesJar + archives androidJavadocsJar +} \ No newline at end of file diff --git a/scripts/android-studio-robolectric-support.gradle b/scripts/android-studio-robolectric-support.gradle new file mode 100644 index 00000000..ba56c8ef --- /dev/null +++ b/scripts/android-studio-robolectric-support.gradle @@ -0,0 +1,58 @@ +apply plugin: 'idea' +// workaround to use android studio and robolectric without build classpath effort +// the 'outputDir' is used as reference to the resource directory, found no other way +// ** current has this workaround no effect, since android studio 6.0 ** +idea { + module { + outputDir = file('build/resources/testDebug') + testOutputDir = file('build/test-classes/debug') + } +} + +// new workaround to force add custom output dirs for android studio +task addTest { + def file = file(project.name + ".iml") + doLast { + try { + def parsedXml = (new XmlParser()).parse(file) + def node = parsedXml.component[1] + def outputNode = parsedXml.component[1].output[0] + def outputTestNode = parsedXml.component[1].'output-test'[0] + def rewrite = false + + new Node(node, 'sourceFolder', ['url': 'file://$MODULE_DIR$/' + "${it}", 'isTestSource': "true"]) + + if(outputNode == null) { + new Node(node, 'output', ['url': 'file://$MODULE_DIR$/build/resources/testDebug']) + } else { + if(outputNode.attributes['url'] != 'file://$MODULE_DIR$/build/resources/testDebug') { + outputNode.attributes = ['url': 'file://$MODULE_DIR$/build/resources/testDebug'] + rewrite = true + } + } + + if(outputTestNode == null) { + new Node(node, 'output-test', ['url': 'file://$MODULE_DIR$/build/test-classes/debug']) + } else { + if(outputTestNode.attributes['url'] != 'file://$MODULE_DIR$/build/test-classes/debug') { + outputTestNode.attributes = ['url': 'file://$MODULE_DIR$/build/test-classes/debug'] + rewrite = true + } + } + + if(rewrite) { + def writer = new StringWriter() + new XmlNodePrinter(new PrintWriter(writer)).print(parsedXml) + file.text = writer.toString() + } + } catch (FileNotFoundException e) { + // iml not found, common on command line only builds + } + + } +} + +// always do the addtest on prebuild +gradle.projectsEvaluated { + testDebugClasses.dependsOn(addTest) +} \ No newline at end of file diff --git a/scripts/install-custom-gradle-test-plugin.sh b/scripts/install-custom-gradle-test-plugin.sh new file mode 100755 index 00000000..85c13d95 --- /dev/null +++ b/scripts/install-custom-gradle-test-plugin.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +mkdir temp +cd temp + + git clone https://github.com/nenick/gradle-android-test-plugin.git + cd gradle-android-test-plugin + + echo "rootProject.name = 'gradle-android-test-plugin-parent'" > settings.gradle + echo "include ':gradle-android-test-plugin'" >> settings.gradle + + ./gradlew :gradle-android-test-plugin:install + + cd .. +cd .. \ No newline at end of file diff --git a/scripts/jacoco-support.gradle b/scripts/jacoco-support.gradle new file mode 100644 index 00000000..0e8fecc2 --- /dev/null +++ b/scripts/jacoco-support.gradle @@ -0,0 +1,26 @@ +jacoco { + toolVersion = "0.7.0.201403182114" +} + +coverageSourceDirs = [ + '../client/src/main/java', + '../client/build/source/apt/debug', + '../client/build/generated/source/db', + '../client/build/generated/source/buildConfig/debug', + '../client/build/generated/source/r/debug'] + +jacocoTestReport { + reports { + xml.enabled = false + html.enabled = true + } + // class R is used, but usage will not be covered, so ignore this class from report + classDirectories = fileTree(dir: '../client/build/intermediates/classes/debug', exclude: 'com/example/R*.class') + additionalSourceDirs = files(coverageSourceDirs) + executionData = files('build/jacoco/testDebug.exec') +} + +// just clean up dashboard, following reports are not of interest +testRelease.reports.html.enabled = false +testRelease.reports.junitXml.enabled = false +testDebug.reports.junitXml.enabled = false \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..2e88badc --- /dev/null +++ b/settings.gradle @@ -0,0 +1,6 @@ +include ':js-android-sdk-client' +include ':js-android-sdk-ui' +include ':unitTests' + +project(':js-android-sdk-client').projectDir = "$rootDir/client" as File +project(':js-android-sdk-ui').projectDir = "$rootDir/ui" as File \ No newline at end of file diff --git a/ui/AndroidManifest.xml b/ui/AndroidManifest.xml index b6b45d89..6daca94c 100644 --- a/ui/AndroidManifest.xml +++ b/ui/AndroidManifest.xml @@ -24,13 +24,8 @@ --> - - - + package="com.jaspersoft.android.sdk.ui"> + + diff --git a/ui/build.gradle b/ui/build.gradle new file mode 100644 index 00000000..a4ce1587 --- /dev/null +++ b/ui/build.gradle @@ -0,0 +1,48 @@ +apply plugin: 'com.android.library' +apply plugin: 'android-maven' + +description = 'js-android-sdk-ui' + +ext { + PUBLISH_GROUP_ID = group + PUBLISH_ARTIFACT_ID = description + PUBLISH_VERSION = '1.9' +} + + +android { + compileSdkVersion androidCompileSdkVersion + buildToolsVersion androidBuildToolsVersion + + defaultConfig { + minSdkVersion androidMinSdkVersion + targetSdkVersion androidTargetSdkVersion + + versionCode 9010900 + versionName version + } + + lintOptions { + abortOnError false + } + + packagingOptions { + exclude 'asm-license.txt' + exclude 'NOTICE' + exclude 'LICENSE' + exclude 'LICENSE.txt' + exclude 'META-INF/license.txt' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/LICENSE' + exclude 'META-INF/notice.txt' + exclude 'META-INF/NOTICE.txt' + exclude 'META-INF/NOTICE' + } +} + + +dependencies { + compile project(':js-android-sdk-client') +} + +apply from: '../scripts/android-release-aar.gradle' \ No newline at end of file diff --git a/ui/pom.xml b/ui/pom.xml deleted file mode 100644 index e8831903..00000000 --- a/ui/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - 4.0.0 - - - js-android-sdk-aggregator - com.jaspersoft.android.sdk - 1.8 - - - js-android-sdk-ui - 1.8 - apklib - - - - com.google.android - android - - - com.jaspersoft.android.sdk - js-android-sdk-client - 1.8 - provided - - - - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - - - org.apache.maven.plugins - maven-source-plugin - - - - - \ No newline at end of file diff --git a/ui/res/drawable-hdpi/ic_action_date_picker.png b/ui/res/drawable-hdpi/ic_action_date_picker.png deleted file mode 100644 index 29157092..00000000 Binary files a/ui/res/drawable-hdpi/ic_action_date_picker.png and /dev/null differ diff --git a/ui/res/drawable-hdpi/ic_action_time_picker.png b/ui/res/drawable-hdpi/ic_action_time_picker.png deleted file mode 100644 index 6758e1c4..00000000 Binary files a/ui/res/drawable-hdpi/ic_action_time_picker.png and /dev/null differ diff --git a/ui/res/drawable-ldpi/ic_action_date_picker.png b/ui/res/drawable-ldpi/ic_action_date_picker.png deleted file mode 100644 index 9bb87ae2..00000000 Binary files a/ui/res/drawable-ldpi/ic_action_date_picker.png and /dev/null differ diff --git a/ui/res/drawable-ldpi/ic_action_time_picker.png b/ui/res/drawable-ldpi/ic_action_time_picker.png deleted file mode 100644 index 1a909fdb..00000000 Binary files a/ui/res/drawable-ldpi/ic_action_time_picker.png and /dev/null differ diff --git a/ui/res/drawable-mdpi/ic_action_date_picker.png b/ui/res/drawable-mdpi/ic_action_date_picker.png deleted file mode 100644 index 6d312aa2..00000000 Binary files a/ui/res/drawable-mdpi/ic_action_date_picker.png and /dev/null differ diff --git a/ui/res/drawable-mdpi/ic_action_time_picker.png b/ui/res/drawable-mdpi/ic_action_time_picker.png deleted file mode 100644 index a6a0f823..00000000 Binary files a/ui/res/drawable-mdpi/ic_action_time_picker.png and /dev/null differ diff --git a/ui/res/drawable-xhdpi/ic_action_date_picker.png b/ui/res/drawable-xhdpi/ic_action_date_picker.png deleted file mode 100644 index 29952813..00000000 Binary files a/ui/res/drawable-xhdpi/ic_action_date_picker.png and /dev/null differ diff --git a/ui/res/drawable-xhdpi/ic_action_time_picker.png b/ui/res/drawable-xhdpi/ic_action_time_picker.png deleted file mode 100644 index d5f73862..00000000 Binary files a/ui/res/drawable-xhdpi/ic_action_time_picker.png and /dev/null differ diff --git a/ui/src/main/AndroidManifest.xml b/ui/src/main/AndroidManifest.xml new file mode 100644 index 00000000..ef105fdb --- /dev/null +++ b/ui/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/FileArrayAdapter.java b/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/FileArrayAdapter.java index c2c99042..93f7e059 100644 --- a/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/FileArrayAdapter.java +++ b/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/FileArrayAdapter.java @@ -38,6 +38,7 @@ import java.io.File; import java.util.Arrays; +import java.util.EnumMap; import java.util.List; /** @@ -48,45 +49,87 @@ */ public class FileArrayAdapter extends ArrayAdapter { - private final Context context; - private final List files; + private LayoutInfo layoutInfo; + private EnumMap drawableIdsMap; + @Deprecated public FileArrayAdapter(Context context, File[] files) { this(context, Arrays.asList(files)); } - public FileArrayAdapter(Context context, List files) { - super(context, R.layout.file_list_item, files); - this.context = context; - this.files = files; + public FileArrayAdapter(Context context, LayoutInfo layoutInfo, File[] files) { + this(context, layoutInfo, Arrays.asList(files)); } - @Override - public View getView(int position, View convertView, ViewGroup parent) { - File file = files.get(position); + public FileArrayAdapter(Context context, LayoutInfo layoutInfo, + EnumMap drawableIdsMap, File[] files) { + this(context, layoutInfo, drawableIdsMap, Arrays.asList(files)); + } - String fileName = file.getName(); - String baseName = FileUtils.getBaseName(fileName); - String extension = FileUtils.getExtension(fileName); + @Deprecated + public FileArrayAdapter(Context context, List files) { + this(context, new LayoutInfo(R.layout.file_list_item), new EnumMap(FileType.class), files); + layoutInfo.setIconViewId(R.id.file_list_item_icon); + layoutInfo.setLabelViewId(R.id.file_list_item_label); + layoutInfo.setDateViewId(R.id.file_list_item_date); + layoutInfo.setSizeViewId(R.id.file_list_item_size); - Drawable icon = getFileIconByExtension(extension); - String dateModified = getFormattedDateModified(file); - String size = getHumanReadableFileSize(file); + drawableIdsMap.put(FileType.HTML, R.drawable.ic_type_html); + drawableIdsMap.put(FileType.PDF, R.drawable.ic_type_pdf); + drawableIdsMap.put(FileType.XLS, R.drawable.ic_type_xls); + drawableIdsMap.put(FileType.UNKNOWN, R.drawable.ic_type_unknown); + } - LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View rowView = inflater.inflate(R.layout.file_list_item, parent, false); + public FileArrayAdapter(Context context, LayoutInfo layoutInfo, List files) { + this(context, layoutInfo, null, files); + } - ImageView imageView = (ImageView) rowView.findViewById(R.id.file_list_item_icon); - TextView labelView = (TextView) rowView.findViewById(R.id.file_list_item_label); - TextView dateView = (TextView) rowView.findViewById(R.id.file_list_item_date); - TextView sizeView = (TextView) rowView.findViewById(R.id.file_list_item_size); + public FileArrayAdapter(Context context, LayoutInfo layoutInfo, + EnumMap drawableIdsMap, List files) { + super(context, layoutInfo.layoutResId, files); + this.layoutInfo = layoutInfo; + this.drawableIdsMap = drawableIdsMap; + } - imageView.setImageDrawable(icon); - labelView.setText(baseName); - dateView.setText(dateModified); - sizeView.setText(size); + @Override + public View getView(int position, View convertView, ViewGroup parent) { + File file = getItem(position); + + // reuse views + View rowView = convertView; + if (rowView == null) { + LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + rowView = inflater.inflate(layoutInfo.getLayoutResId(), parent, false); + // configure view holder + ViewHolder viewHolder = new ViewHolder(); + viewHolder.iconView = (ImageView) rowView.findViewById(layoutInfo.getIconViewId()); + viewHolder.labelView = (TextView) rowView.findViewById(layoutInfo.getLabelViewId()); + viewHolder.dateView = (TextView) rowView.findViewById(layoutInfo.getDateViewId()); + viewHolder.sizeView = (TextView) rowView.findViewById(layoutInfo.getSizeViewId()); + rowView.setTag(viewHolder); + } + // fill data + ViewHolder viewHolder = (ViewHolder) rowView.getTag(); + if (viewHolder.iconView != null && drawableIdsMap != null) { + String extension = FileUtils.getExtension(file.getName()); + Drawable icon = getFileIconByExtension(extension); + viewHolder.iconView.setImageDrawable(icon); + } + if (viewHolder.labelView != null) { + String baseName = FileUtils.getBaseName(file.getName()); + viewHolder.labelView.setText(baseName); + } + if (viewHolder.dateView != null) { + String dateModified = getFormattedDateModified(file); + viewHolder.dateView.setText(dateModified); + } + if (viewHolder.sizeView != null) { + String size = getHumanReadableFileSize(file); + viewHolder.sizeView.setText(size); + } + // return configured view return rowView; } @@ -96,28 +139,20 @@ public View getView(int position, View convertView, ViewGroup parent) { private Drawable getFileIconByExtension(String extension) { FileType type = getFileTypeByExtension(extension); + int drawableResId = drawableIdsMap.get(type); + return getContext().getResources().getDrawable(drawableResId); + } - Drawable fileIcon; - switch (type) { - case HTML: - fileIcon = context.getResources().getDrawable(R.drawable.ic_type_html); - break; - case PDF: - fileIcon = context.getResources().getDrawable(R.drawable.ic_type_pdf); - break; - case XLS: - fileIcon = context.getResources().getDrawable(R.drawable.ic_type_xls); - break; - default: - fileIcon = context.getResources().getDrawable(R.drawable.ic_type_unknown); - break; - } - - return fileIcon; + private FileType getFileTypeByExtension(String extension) { + try { + return FileType.valueOf(extension); + } catch (IllegalArgumentException ex) { + return FileType.UNKNOWN; + } } private String getFormattedDateModified(File file) { - return DateUtils.formatDateTime(context, file.lastModified(), + return DateUtils.formatDateTime(getContext(), file.lastModified(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_YEAR | @@ -131,23 +166,70 @@ private String getHumanReadableFileSize(File file) { return FileUtils.getHumanReadableByteCount(bytes); } - private FileType getFileTypeByExtension(String extension) { - try { - return FileType.valueOf(extension); - } catch (IllegalArgumentException ex) { - return FileType.UNKNOWN; - } - } - //--------------------------------------------------------------------- // Nested Classes //--------------------------------------------------------------------- - private enum FileType { + public enum FileType { HTML, PDF, XLS, UNKNOWN } + public static class LayoutInfo { + private int layoutResId; + private int iconViewId; + private int labelViewId; + private int dateViewId; + private int sizeViewId; + + public LayoutInfo(int layoutResId) { + this.layoutResId = layoutResId; + } + + public int getLayoutResId() { + return layoutResId; + } + + public int getIconViewId() { + return iconViewId; + } + + public void setIconViewId(int iconViewId) { + this.iconViewId = iconViewId; + } + + public int getLabelViewId() { + return labelViewId; + } + + public void setLabelViewId(int labelViewId) { + this.labelViewId = labelViewId; + } + + public int getDateViewId() { + return dateViewId; + } + + public void setDateViewId(int dateViewId) { + this.dateViewId = dateViewId; + } + + public int getSizeViewId() { + return sizeViewId; + } + + public void setSizeViewId(int sizeViewId) { + this.sizeViewId = sizeViewId; + } + } + + private static class ViewHolder { + private ImageView iconView; + private TextView labelView; + private TextView dateView; + private TextView sizeView; + } + } diff --git a/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/ResourceLookupArrayAdapter.java b/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/ResourceLookupArrayAdapter.java index d4ae0656..886a653e 100644 --- a/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/ResourceLookupArrayAdapter.java +++ b/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/ResourceLookupArrayAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Jaspersoft Corporation. All rights reserved. + * Copyright (C) 2012-2014 Jaspersoft Corporation. All rights reserved. * http://community.jaspersoft.com/project/mobile-sdk-android * * Unless you have purchased a commercial license agreement from Jaspersoft, @@ -35,8 +35,15 @@ import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookup; import com.jaspersoft.android.sdk.ui.R; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.EnumMap; import java.util.List; +import static com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookup.ResourceType; + /** * A concrete ArrayAdapter that is backed by an array of ResourceLookup objects. * @@ -44,47 +51,174 @@ * @since 1.7 */ public class ResourceLookupArrayAdapter extends ArrayAdapter{ - private final Context context; - private final List resourceLookups; + private LayoutInfo layoutInfo; + private EnumMap drawableIdsMap; + private String datetimeFormatPattern = "yyyy-MM-dd HH:mm:ss"; + + public ResourceLookupArrayAdapter(Context context, LayoutInfo layoutInfo, List resourceLookups) { + this(context, layoutInfo, null, resourceLookups); + } + + public ResourceLookupArrayAdapter(Context context, LayoutInfo layoutInfo, + EnumMap drawableIdsMap, + List resourceLookups) { + super(context, layoutInfo.layoutResId, resourceLookups); + this.layoutInfo = layoutInfo; + this.drawableIdsMap = drawableIdsMap; + } + + @Deprecated public ResourceLookupArrayAdapter(Context context, List resourceLookups) { - super(context, R.layout.resource_list_item, resourceLookups); - this.context = context; - this.resourceLookups = resourceLookups; + this(context, new LayoutInfo(R.layout.resource_list_item), + new EnumMap(ResourceType.class), resourceLookups); + + layoutInfo.setIconViewId(R.id.resource_list_item_icon); + layoutInfo.setLabelViewId(R.id.resource_list_item_label); + layoutInfo.setUriViewId(R.id.resource_list_item_uri); + + drawableIdsMap.put(ResourceType.folder, R.drawable.ic_type_folder); + drawableIdsMap.put(ResourceType.reportUnit, R.drawable.ic_type_report); + drawableIdsMap.put(ResourceType.dashboard, R.drawable.ic_type_dashboard); + drawableIdsMap.put(ResourceType.unknown, R.drawable.ic_type_unknown); } @Override public View getView(int position, View convertView, ViewGroup parent) { - ResourceLookup resourceLookup = resourceLookups.get(position); - - Drawable drawable; - switch (resourceLookup.getResourceType()) { - case folder: - drawable = context.getResources().getDrawable(R.drawable.ic_type_folder); - break; - case reportUnit: - drawable = context.getResources().getDrawable(R.drawable.ic_type_report); - break; - case dashboard: - drawable = context.getResources().getDrawable(R.drawable.ic_type_dashboard); - break; - default: - // for an unknown resource - drawable = context.getResources().getDrawable(R.drawable.ic_type_unknown); - break; - } - - LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View rowView = inflater.inflate(R.layout.resource_list_item, parent, false); - - ImageView image = (ImageView) rowView.findViewById(R.id.resource_list_item_icon); - TextView label = (TextView) rowView.findViewById(R.id.resource_list_item_label); - TextView uri = (TextView) rowView.findViewById(R.id.resource_list_item_uri); - - image.setImageDrawable(drawable); - label.setText(resourceLookup.getLabel()); - uri.setText(resourceLookup.getUri()); - + ResourceLookup resourceLookup = getItem(position); + // reuse views + View rowView = convertView; + if (rowView == null) { + LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + rowView = inflater.inflate(layoutInfo.layoutResId, parent, false); + // configure view holder + ViewHolder viewHolder = new ViewHolder(); + viewHolder.iconView = (ImageView) rowView.findViewById(layoutInfo.iconViewId); + viewHolder.labelView = (TextView) rowView.findViewById(layoutInfo.labelViewId); + viewHolder.descriptionView = (TextView) rowView.findViewById(layoutInfo.descriptionViewId); + viewHolder.dateView = (TextView) rowView.findViewById(layoutInfo.dateViewId); + viewHolder.uriView = (TextView) rowView.findViewById(layoutInfo.uriViewId); + rowView.setTag(viewHolder); + } + // fill data + ViewHolder viewHolder = (ViewHolder) rowView.getTag(); + if (viewHolder.iconView != null && drawableIdsMap != null) { + Drawable icon = getIconByType(resourceLookup.getResourceType()); + viewHolder.iconView.setImageDrawable(icon); + } + if (viewHolder.labelView != null) { + String label = resourceLookup.getLabel(); + viewHolder.labelView.setText(label); + } + if (viewHolder.descriptionView != null) { + String description = resourceLookup.getDescription(); + viewHolder.descriptionView.setText(description); + } + if (viewHolder.dateView != null) { + String date = formatDateString(resourceLookup.getUpdateDate()); + viewHolder.dateView.setText(date); + } + if (viewHolder.uriView != null) { + String uri = resourceLookup.getUri(); + viewHolder.uriView.setText(uri); + } + // return configured view return rowView; } -} + + public void setDatetimeFormatPattern(String datetimeFormatPattern) { + this.datetimeFormatPattern = datetimeFormatPattern; + } + + //--------------------------------------------------------------------- + // Helper methods + //--------------------------------------------------------------------- + + private Drawable getIconByType(ResourceType type) { + type = (drawableIdsMap.containsKey(type)) ? type : ResourceType.unknown; + int drawableResId = drawableIdsMap.get(type); + return getContext().getResources().getDrawable(drawableResId); + } + + private String formatDateString(String updateDate) { + updateDate = (updateDate == null) ? "" : updateDate; + try { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datetimeFormatPattern); + Date dateValue = simpleDateFormat.parse(updateDate); + DateFormat dateFormat = DateFormat.getDateInstance(); + return dateFormat.format(dateValue); + } catch (ParseException ex) { + return updateDate; + } + } + + //--------------------------------------------------------------------- + // Nested Classes + //--------------------------------------------------------------------- + + public static class LayoutInfo { + private int layoutResId; + private int iconViewId; + private int labelViewId; + private int descriptionViewId; + private int dateViewId; + private int uriViewId; + + public LayoutInfo(int layoutResId) { + this.layoutResId = layoutResId; + } + + public int getLayoutResId() { + return layoutResId; + } + + public int getIconViewId() { + return iconViewId; + } + + public void setIconViewId(int iconViewId) { + this.iconViewId = iconViewId; + } + + public int getLabelViewId() { + return labelViewId; + } + + public void setLabelViewId(int labelViewId) { + this.labelViewId = labelViewId; + } + + public int getDescriptionViewId() { + return descriptionViewId; + } + + public void setDescriptionViewId(int descriptionViewId) { + this.descriptionViewId = descriptionViewId; + } + + public int getDateViewId() { + return dateViewId; + } + + public void setDateViewId(int dateViewId) { + this.dateViewId = dateViewId; + } + + public int getUriViewId() { + return uriViewId; + } + + public void setUriViewId(int uriViewId) { + this.uriViewId = uriViewId; + } + } + + private static class ViewHolder { + private ImageView iconView; + private TextView labelView; + private TextView descriptionView; + private TextView dateView; + private TextView uriView; + } + +} \ No newline at end of file diff --git a/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/ResourceLookupEndlessAdapter.java b/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/ResourceLookupEndlessAdapter.java new file mode 100644 index 00000000..4c1f7620 --- /dev/null +++ b/ui/src/main/java/com/jaspersoft/android/sdk/ui/adapters/ResourceLookupEndlessAdapter.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2012-2014 Jaspersoft Corporation. + * Portions (C) 2008-2009 CommonsWare, LLC + * Portions (C) 2009 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.jaspersoft.android.sdk.ui.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookup; + +import java.util.EnumMap; +import java.util.List; + +import static com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookup.ResourceType; + +/** + * @author Ivan Gadzhega + * @since 2.0 + */ +public class ResourceLookupEndlessAdapter extends ResourceLookupArrayAdapter { + + private LayoutInfo layoutInfo; + private boolean keepOnAppending; + private View pendingView; + + public ResourceLookupEndlessAdapter(Context context, LayoutInfo layoutInfo, List resourceLookups) { + super(context, layoutInfo, resourceLookups); + this.layoutInfo = layoutInfo; + } + + public ResourceLookupEndlessAdapter(Context context, LayoutInfo layoutInfo, EnumMap drawableIdsMap, + List resourceLookups) { + super(context, layoutInfo, drawableIdsMap, resourceLookups); + this.layoutInfo = layoutInfo; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (keepOnAppending && position == super.getCount()) { + return getPendingView(parent); + } else { + return super.getView(position, convertView, parent); + } + } + + @Override + public int getCount() { + return (keepOnAppending) ? super.getCount() + 1 : super.getCount(); + } + + public int getItemViewType(int position) { + return (position < super.getCount()) ? super.getItemViewType(position) : IGNORE_ITEM_VIEW_TYPE; + } + + public int getViewTypeCount() { + return super.getViewTypeCount() + 1; + } + + @Override + public ResourceLookup getItem(int position) { + return (position < super.getCount()) ? super.getItem(position) : null; + } + + //--------------------------------------------------------------------- + // Helper methods + //--------------------------------------------------------------------- + + private View getPendingView(ViewGroup parent) { + if (pendingView == null) { + LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + pendingView = inflater.inflate(layoutInfo.getPendingViewResId(), parent, false); + } + return pendingView; + } + + //--------------------------------------------------------------------- + // Getters & Setters + //--------------------------------------------------------------------- + + public void setKeepOnAppending(boolean keepOnAppending) { + this.keepOnAppending = keepOnAppending; + } + + public boolean isKeepOnAppending() { + return keepOnAppending; + } + + //--------------------------------------------------------------------- + // Nested Classes + //--------------------------------------------------------------------- + + public static class LayoutInfo extends ResourceLookupArrayAdapter.LayoutInfo { + + private int pendingViewResId; + + public LayoutInfo(int layoutResId) { + super(layoutResId); + } + + public int getPendingViewResId() { + return pendingViewResId; + } + + public void setPendingViewResId(int pendingViewResId) { + this.pendingViewResId = pendingViewResId; + } + } + +} \ No newline at end of file diff --git a/ui/src/main/java/com/jaspersoft/android/sdk/ui/widget/MultiSelectSpinner.java b/ui/src/main/java/com/jaspersoft/android/sdk/ui/widget/MultiSelectSpinner.java index 2e027581..797a1f0a 100644 --- a/ui/src/main/java/com/jaspersoft/android/sdk/ui/widget/MultiSelectSpinner.java +++ b/ui/src/main/java/com/jaspersoft/android/sdk/ui/widget/MultiSelectSpinner.java @@ -28,11 +28,17 @@ import android.content.Context; import android.content.DialogInterface; import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; +import android.widget.Button; import android.widget.Spinner; + import com.jaspersoft.android.sdk.ui.R; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -52,6 +58,7 @@ public class MultiSelectSpinner extends Spinner implements DialogInterface.On private List items; CharSequence[] stringItems; private boolean[] checkedItems; + private boolean[] defaultCheckedItems; /** * the text that displays on the spinner if there is nothing selected. */ @@ -76,33 +83,25 @@ public MultiSelectSpinner(Context context, AttributeSet attrs, int defStyle) { /** * This method will be invoked when an item in the dialog is clicked. * - * @param dialog The dialog where the selection was made. - * @param which The position of the item in the list that was clicked. + * @param dialog The dialog where the selection was made. + * @param which The position of the item in the list that was clicked. * @param isChecked True if the click checked the item, else false. */ @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { checkedItems[which] = isChecked; + updateState(false); } @Override public boolean performClick() { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); // The prompt to display when the dialog is shown if (getPrompt() != null) { builder.setTitle(getPrompt()); } + defaultCheckedItems = Arrays.copyOf(checkedItems, checkedItems.length); builder.setMultiChoiceItems(stringItems, checkedItems, this); - builder.setNegativeButton(R.string.mss_btn_uncheck_all, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - unselectAll(); - updateState(); - performClick(); - } - - }); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override @@ -110,14 +109,76 @@ public void onClick(DialogInterface dialog, int which) { updateState(); } }); - builder.show(); + builder.setNegativeButton(R.string.mss_btn_check_all, null); + + final AlertDialog dialog = builder.create(); + dialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialogInterface) { + dialog.getListView().setAdapter(initCustomAdapter(dialog)); + Button button = dialog.getButton(AlertDialog.BUTTON_NEGATIVE); + button.setText(ifAnyChecked() ? R.string.mss_btn_uncheck_all : R.string.mss_btn_check_all); + + dialog.getButton(AlertDialog.BUTTON_NEGATIVE) + .setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + Button button = (Button) view; + boolean ifAnyChecked = ifAnyChecked(); + button.setText(ifAnyChecked ? R.string.mss_btn_check_all : R.string.mss_btn_uncheck_all); + + if (ifAnyChecked) { + unselectAll(); + } else { + selectAll(); + } + + dialog.getListView().setAdapter(initCustomAdapter(dialog)); + updateState(false); + } + }); + } + }); + dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + checkedItems = defaultCheckedItems; + updateState(false); + } + }); + dialog.show(); return true; } + private boolean ifAnyChecked() { + boolean ifAnyCheckedMask = false; + for (boolean checkedItem : checkedItems) { + ifAnyCheckedMask = ifAnyCheckedMask || checkedItem; + } + return ifAnyCheckedMask; + } + + private BaseAdapter initCustomAdapter(final AlertDialog dialog) { + return new ArrayAdapter( + getContext(), R.layout.select_dialog_multichoice, android.R.id.text1, stringItems) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = super.getView(position, convertView, parent); + if (checkedItems != null) { + boolean isItemChecked = checkedItems[position]; + if (isItemChecked) { + dialog.getListView().setItemChecked(position, true); + } + } + return view; + } + }; + } + /** * Gets a list of items displayed in the spinner. * - * @return list of items + * @return list of items */ public List getItems() { return items; @@ -135,7 +196,7 @@ public void setItemsList(List items) { /** * Sets a list of items to be displayed in the spinner. * - * @param items list of items + * @param items list of items * @param defaultText the text that displays on the spinner if there is nothing selected. */ public void setItemsList(List items, String defaultText) { @@ -154,7 +215,7 @@ public void setItemsList(List items, String defaultText) { } ArrayAdapter adapter = new ArrayAdapter(getContext(), - android.R.layout.simple_spinner_item, new String[] { defaultText }); + android.R.layout.simple_spinner_item, new String[]{defaultText}); setAdapter(adapter); } @@ -206,7 +267,7 @@ public void setSelection(List positions) { */ public List getSelectedItems() { List selectedItems = new ArrayList(); - for(Integer position : getSelectedItemsPositions()) { + for (Integer position : getSelectedItemsPositions()) { selectedItems.add(items.get(position)); } return selectedItems; @@ -234,11 +295,15 @@ public void setSelection(int position, boolean animate) { //--------------------------------------------------------------------- private void updateState() { + updateState(true); + } + + private void updateState(boolean notifyListener) { // refresh text on spinner StringBuilder spinnerBuilder = new StringBuilder(); for (int i = 0; i < stringItems.length; i++) { if (checkedItems[i]) { - if(spinnerBuilder.length() > 0) { + if (spinnerBuilder.length() > 0) { spinnerBuilder.append(TEXT_SEPARATOR); } if (spinnerBuilder.length() > TEXT_MAX_LENGTH) { @@ -249,21 +314,29 @@ private void updateState() { } } - String spinnerText = (spinnerBuilder.length() > 0) ? spinnerBuilder.toString() : defaultText ; + String spinnerText = (spinnerBuilder.length() > 0) ? spinnerBuilder.toString() : defaultText; ArrayAdapter adapter = new ArrayAdapter(getContext(), android.R.layout.simple_spinner_item, - new String[] { spinnerText }); + new String[]{spinnerText}); setAdapter(adapter); - if (onItemsSelectedListener != null) { + if (onItemsSelectedListener != null && notifyListener) { onItemsSelectedListener.onItemsSelected(getSelectedItems()); } } + private void selectAll() { + setSelection(true); + } + private void unselectAll() { - for (int i=0; i < checkedItems.length; i++) { - checkedItems[i] = false; + setSelection(false); + } + + private void setSelection(boolean isSelected) { + for (int i = 0; i < checkedItems.length; i++) { + checkedItems[i] = isSelected; } } } diff --git a/ui/res/color/cs_blue_white.xml b/ui/src/main/res/color/cs_blue_white.xml similarity index 100% rename from ui/res/color/cs_blue_white.xml rename to ui/src/main/res/color/cs_blue_white.xml diff --git a/ui/res/color/cs_dark_grey_white.xml b/ui/src/main/res/color/cs_dark_grey_white.xml similarity index 100% rename from ui/res/color/cs_dark_grey_white.xml rename to ui/src/main/res/color/cs_dark_grey_white.xml diff --git a/ui/res/color/cs_grey_white.xml b/ui/src/main/res/color/cs_grey_white.xml similarity index 100% rename from ui/res/color/cs_grey_white.xml rename to ui/src/main/res/color/cs_grey_white.xml diff --git a/ui/src/main/res/color/cs_light_grey_white.xml b/ui/src/main/res/color/cs_light_grey_white.xml new file mode 100644 index 00000000..779785f7 --- /dev/null +++ b/ui/src/main/res/color/cs_light_grey_white.xml @@ -0,0 +1,41 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ui/res/color/cs_orange_white.xml b/ui/src/main/res/color/cs_orange_white.xml similarity index 100% rename from ui/res/color/cs_orange_white.xml rename to ui/src/main/res/color/cs_orange_white.xml diff --git a/ui/res/drawable-hdpi/ic_action_add.png b/ui/src/main/res/drawable-hdpi/ic_action_add.png similarity index 100% rename from ui/res/drawable-hdpi/ic_action_add.png rename to ui/src/main/res/drawable-hdpi/ic_action_add.png diff --git a/ui/src/main/res/drawable-hdpi/ic_action_date_picker.png b/ui/src/main/res/drawable-hdpi/ic_action_date_picker.png new file mode 100644 index 00000000..eb14c4d8 Binary files /dev/null and b/ui/src/main/res/drawable-hdpi/ic_action_date_picker.png differ diff --git a/ui/src/main/res/drawable-hdpi/ic_action_time_picker.png b/ui/src/main/res/drawable-hdpi/ic_action_time_picker.png new file mode 100644 index 00000000..96c2b0ed Binary files /dev/null and b/ui/src/main/res/drawable-hdpi/ic_action_time_picker.png differ diff --git a/ui/res/drawable-hdpi/ic_menu_add.png b/ui/src/main/res/drawable-hdpi/ic_menu_add.png similarity index 100% rename from ui/res/drawable-hdpi/ic_menu_add.png rename to ui/src/main/res/drawable-hdpi/ic_menu_add.png diff --git a/ui/res/drawable-hdpi/ic_menu_logout.png b/ui/src/main/res/drawable-hdpi/ic_menu_logout.png similarity index 100% rename from ui/res/drawable-hdpi/ic_menu_logout.png rename to ui/src/main/res/drawable-hdpi/ic_menu_logout.png diff --git a/ui/res/drawable-hdpi/ic_menu_refresh.png b/ui/src/main/res/drawable-hdpi/ic_menu_refresh.png similarity index 100% rename from ui/res/drawable-hdpi/ic_menu_refresh.png rename to ui/src/main/res/drawable-hdpi/ic_menu_refresh.png diff --git a/ui/res/drawable-hdpi/ic_menu_server_profile.png b/ui/src/main/res/drawable-hdpi/ic_menu_server_profile.png similarity index 100% rename from ui/res/drawable-hdpi/ic_menu_server_profile.png rename to ui/src/main/res/drawable-hdpi/ic_menu_server_profile.png diff --git a/ui/res/drawable-hdpi/ic_type_dashboard.png b/ui/src/main/res/drawable-hdpi/ic_type_dashboard.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_dashboard.png rename to ui/src/main/res/drawable-hdpi/ic_type_dashboard.png diff --git a/ui/res/drawable-hdpi/ic_type_folder.png b/ui/src/main/res/drawable-hdpi/ic_type_folder.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_folder.png rename to ui/src/main/res/drawable-hdpi/ic_type_folder.png diff --git a/ui/res/drawable-hdpi/ic_type_html.png b/ui/src/main/res/drawable-hdpi/ic_type_html.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_html.png rename to ui/src/main/res/drawable-hdpi/ic_type_html.png diff --git a/ui/res/drawable-hdpi/ic_type_image.png b/ui/src/main/res/drawable-hdpi/ic_type_image.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_image.png rename to ui/src/main/res/drawable-hdpi/ic_type_image.png diff --git a/ui/res/drawable-hdpi/ic_type_pdf.png b/ui/src/main/res/drawable-hdpi/ic_type_pdf.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_pdf.png rename to ui/src/main/res/drawable-hdpi/ic_type_pdf.png diff --git a/ui/res/drawable-hdpi/ic_type_report.png b/ui/src/main/res/drawable-hdpi/ic_type_report.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_report.png rename to ui/src/main/res/drawable-hdpi/ic_type_report.png diff --git a/ui/res/drawable-hdpi/ic_type_server_profile.png b/ui/src/main/res/drawable-hdpi/ic_type_server_profile.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_server_profile.png rename to ui/src/main/res/drawable-hdpi/ic_type_server_profile.png diff --git a/ui/res/drawable-hdpi/ic_type_text.png b/ui/src/main/res/drawable-hdpi/ic_type_text.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_text.png rename to ui/src/main/res/drawable-hdpi/ic_type_text.png diff --git a/ui/res/drawable-hdpi/ic_type_unknown.png b/ui/src/main/res/drawable-hdpi/ic_type_unknown.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_unknown.png rename to ui/src/main/res/drawable-hdpi/ic_type_unknown.png diff --git a/ui/res/drawable-hdpi/ic_type_xls.png b/ui/src/main/res/drawable-hdpi/ic_type_xls.png similarity index 100% rename from ui/res/drawable-hdpi/ic_type_xls.png rename to ui/src/main/res/drawable-hdpi/ic_type_xls.png diff --git a/ui/res/drawable-ldpi/ic_action_add.png b/ui/src/main/res/drawable-ldpi/ic_action_add.png similarity index 100% rename from ui/res/drawable-ldpi/ic_action_add.png rename to ui/src/main/res/drawable-ldpi/ic_action_add.png diff --git a/ui/src/main/res/drawable-ldpi/ic_action_date_picker.png b/ui/src/main/res/drawable-ldpi/ic_action_date_picker.png new file mode 100644 index 00000000..233e7b65 Binary files /dev/null and b/ui/src/main/res/drawable-ldpi/ic_action_date_picker.png differ diff --git a/ui/src/main/res/drawable-ldpi/ic_action_time_picker.png b/ui/src/main/res/drawable-ldpi/ic_action_time_picker.png new file mode 100644 index 00000000..2a23d6b6 Binary files /dev/null and b/ui/src/main/res/drawable-ldpi/ic_action_time_picker.png differ diff --git a/ui/res/drawable-ldpi/ic_menu_add.png b/ui/src/main/res/drawable-ldpi/ic_menu_add.png similarity index 100% rename from ui/res/drawable-ldpi/ic_menu_add.png rename to ui/src/main/res/drawable-ldpi/ic_menu_add.png diff --git a/ui/res/drawable-ldpi/ic_menu_logout.png b/ui/src/main/res/drawable-ldpi/ic_menu_logout.png similarity index 100% rename from ui/res/drawable-ldpi/ic_menu_logout.png rename to ui/src/main/res/drawable-ldpi/ic_menu_logout.png diff --git a/ui/res/drawable-ldpi/ic_menu_refresh.png b/ui/src/main/res/drawable-ldpi/ic_menu_refresh.png similarity index 100% rename from ui/res/drawable-ldpi/ic_menu_refresh.png rename to ui/src/main/res/drawable-ldpi/ic_menu_refresh.png diff --git a/ui/res/drawable-ldpi/ic_menu_server_profile.png b/ui/src/main/res/drawable-ldpi/ic_menu_server_profile.png similarity index 100% rename from ui/res/drawable-ldpi/ic_menu_server_profile.png rename to ui/src/main/res/drawable-ldpi/ic_menu_server_profile.png diff --git a/ui/res/drawable-ldpi/ic_type_dashboard.png b/ui/src/main/res/drawable-ldpi/ic_type_dashboard.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_dashboard.png rename to ui/src/main/res/drawable-ldpi/ic_type_dashboard.png diff --git a/ui/res/drawable-ldpi/ic_type_folder.png b/ui/src/main/res/drawable-ldpi/ic_type_folder.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_folder.png rename to ui/src/main/res/drawable-ldpi/ic_type_folder.png diff --git a/ui/res/drawable-ldpi/ic_type_html.png b/ui/src/main/res/drawable-ldpi/ic_type_html.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_html.png rename to ui/src/main/res/drawable-ldpi/ic_type_html.png diff --git a/ui/res/drawable-ldpi/ic_type_image.png b/ui/src/main/res/drawable-ldpi/ic_type_image.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_image.png rename to ui/src/main/res/drawable-ldpi/ic_type_image.png diff --git a/ui/res/drawable-ldpi/ic_type_pdf.png b/ui/src/main/res/drawable-ldpi/ic_type_pdf.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_pdf.png rename to ui/src/main/res/drawable-ldpi/ic_type_pdf.png diff --git a/ui/res/drawable-ldpi/ic_type_report.png b/ui/src/main/res/drawable-ldpi/ic_type_report.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_report.png rename to ui/src/main/res/drawable-ldpi/ic_type_report.png diff --git a/ui/res/drawable-ldpi/ic_type_server_profile.png b/ui/src/main/res/drawable-ldpi/ic_type_server_profile.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_server_profile.png rename to ui/src/main/res/drawable-ldpi/ic_type_server_profile.png diff --git a/ui/res/drawable-ldpi/ic_type_text.png b/ui/src/main/res/drawable-ldpi/ic_type_text.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_text.png rename to ui/src/main/res/drawable-ldpi/ic_type_text.png diff --git a/ui/res/drawable-ldpi/ic_type_unknown.png b/ui/src/main/res/drawable-ldpi/ic_type_unknown.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_unknown.png rename to ui/src/main/res/drawable-ldpi/ic_type_unknown.png diff --git a/ui/res/drawable-ldpi/ic_type_xls.png b/ui/src/main/res/drawable-ldpi/ic_type_xls.png similarity index 100% rename from ui/res/drawable-ldpi/ic_type_xls.png rename to ui/src/main/res/drawable-ldpi/ic_type_xls.png diff --git a/ui/res/drawable-mdpi/ic_action_add.png b/ui/src/main/res/drawable-mdpi/ic_action_add.png similarity index 100% rename from ui/res/drawable-mdpi/ic_action_add.png rename to ui/src/main/res/drawable-mdpi/ic_action_add.png diff --git a/ui/src/main/res/drawable-mdpi/ic_action_date_picker.png b/ui/src/main/res/drawable-mdpi/ic_action_date_picker.png new file mode 100644 index 00000000..07c23848 Binary files /dev/null and b/ui/src/main/res/drawable-mdpi/ic_action_date_picker.png differ diff --git a/ui/src/main/res/drawable-mdpi/ic_action_time_picker.png b/ui/src/main/res/drawable-mdpi/ic_action_time_picker.png new file mode 100644 index 00000000..407be1d0 Binary files /dev/null and b/ui/src/main/res/drawable-mdpi/ic_action_time_picker.png differ diff --git a/ui/res/drawable-mdpi/ic_menu_add.png b/ui/src/main/res/drawable-mdpi/ic_menu_add.png similarity index 100% rename from ui/res/drawable-mdpi/ic_menu_add.png rename to ui/src/main/res/drawable-mdpi/ic_menu_add.png diff --git a/ui/res/drawable-mdpi/ic_menu_logout.png b/ui/src/main/res/drawable-mdpi/ic_menu_logout.png similarity index 100% rename from ui/res/drawable-mdpi/ic_menu_logout.png rename to ui/src/main/res/drawable-mdpi/ic_menu_logout.png diff --git a/ui/res/drawable-mdpi/ic_menu_refresh.png b/ui/src/main/res/drawable-mdpi/ic_menu_refresh.png similarity index 100% rename from ui/res/drawable-mdpi/ic_menu_refresh.png rename to ui/src/main/res/drawable-mdpi/ic_menu_refresh.png diff --git a/ui/res/drawable-mdpi/ic_menu_server_profile.png b/ui/src/main/res/drawable-mdpi/ic_menu_server_profile.png similarity index 100% rename from ui/res/drawable-mdpi/ic_menu_server_profile.png rename to ui/src/main/res/drawable-mdpi/ic_menu_server_profile.png diff --git a/ui/res/drawable-mdpi/ic_type_dashboard.png b/ui/src/main/res/drawable-mdpi/ic_type_dashboard.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_dashboard.png rename to ui/src/main/res/drawable-mdpi/ic_type_dashboard.png diff --git a/ui/res/drawable-mdpi/ic_type_folder.png b/ui/src/main/res/drawable-mdpi/ic_type_folder.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_folder.png rename to ui/src/main/res/drawable-mdpi/ic_type_folder.png diff --git a/ui/res/drawable-mdpi/ic_type_html.png b/ui/src/main/res/drawable-mdpi/ic_type_html.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_html.png rename to ui/src/main/res/drawable-mdpi/ic_type_html.png diff --git a/ui/res/drawable-mdpi/ic_type_image.png b/ui/src/main/res/drawable-mdpi/ic_type_image.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_image.png rename to ui/src/main/res/drawable-mdpi/ic_type_image.png diff --git a/ui/res/drawable-mdpi/ic_type_pdf.png b/ui/src/main/res/drawable-mdpi/ic_type_pdf.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_pdf.png rename to ui/src/main/res/drawable-mdpi/ic_type_pdf.png diff --git a/ui/res/drawable-mdpi/ic_type_report.png b/ui/src/main/res/drawable-mdpi/ic_type_report.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_report.png rename to ui/src/main/res/drawable-mdpi/ic_type_report.png diff --git a/ui/res/drawable-mdpi/ic_type_server_profile.png b/ui/src/main/res/drawable-mdpi/ic_type_server_profile.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_server_profile.png rename to ui/src/main/res/drawable-mdpi/ic_type_server_profile.png diff --git a/ui/res/drawable-mdpi/ic_type_text.png b/ui/src/main/res/drawable-mdpi/ic_type_text.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_text.png rename to ui/src/main/res/drawable-mdpi/ic_type_text.png diff --git a/ui/res/drawable-mdpi/ic_type_unknown.png b/ui/src/main/res/drawable-mdpi/ic_type_unknown.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_unknown.png rename to ui/src/main/res/drawable-mdpi/ic_type_unknown.png diff --git a/ui/res/drawable-mdpi/ic_type_xls.png b/ui/src/main/res/drawable-mdpi/ic_type_xls.png similarity index 100% rename from ui/res/drawable-mdpi/ic_type_xls.png rename to ui/src/main/res/drawable-mdpi/ic_type_xls.png diff --git a/ui/res/drawable-xhdpi/ic_action_add.png b/ui/src/main/res/drawable-xhdpi/ic_action_add.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_action_add.png rename to ui/src/main/res/drawable-xhdpi/ic_action_add.png diff --git a/ui/src/main/res/drawable-xhdpi/ic_action_date_picker.png b/ui/src/main/res/drawable-xhdpi/ic_action_date_picker.png new file mode 100644 index 00000000..33e96272 Binary files /dev/null and b/ui/src/main/res/drawable-xhdpi/ic_action_date_picker.png differ diff --git a/ui/src/main/res/drawable-xhdpi/ic_action_time_picker.png b/ui/src/main/res/drawable-xhdpi/ic_action_time_picker.png new file mode 100644 index 00000000..68d5de0b Binary files /dev/null and b/ui/src/main/res/drawable-xhdpi/ic_action_time_picker.png differ diff --git a/ui/res/drawable-xhdpi/ic_menu_add.png b/ui/src/main/res/drawable-xhdpi/ic_menu_add.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_menu_add.png rename to ui/src/main/res/drawable-xhdpi/ic_menu_add.png diff --git a/ui/res/drawable-xhdpi/ic_menu_logout.png b/ui/src/main/res/drawable-xhdpi/ic_menu_logout.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_menu_logout.png rename to ui/src/main/res/drawable-xhdpi/ic_menu_logout.png diff --git a/ui/res/drawable-xhdpi/ic_menu_refresh.png b/ui/src/main/res/drawable-xhdpi/ic_menu_refresh.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_menu_refresh.png rename to ui/src/main/res/drawable-xhdpi/ic_menu_refresh.png diff --git a/ui/res/drawable-xhdpi/ic_menu_server_profile.png b/ui/src/main/res/drawable-xhdpi/ic_menu_server_profile.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_menu_server_profile.png rename to ui/src/main/res/drawable-xhdpi/ic_menu_server_profile.png diff --git a/ui/res/drawable-xhdpi/ic_type_dashboard.png b/ui/src/main/res/drawable-xhdpi/ic_type_dashboard.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_dashboard.png rename to ui/src/main/res/drawable-xhdpi/ic_type_dashboard.png diff --git a/ui/res/drawable-xhdpi/ic_type_folder.png b/ui/src/main/res/drawable-xhdpi/ic_type_folder.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_folder.png rename to ui/src/main/res/drawable-xhdpi/ic_type_folder.png diff --git a/ui/res/drawable-xhdpi/ic_type_html.png b/ui/src/main/res/drawable-xhdpi/ic_type_html.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_html.png rename to ui/src/main/res/drawable-xhdpi/ic_type_html.png diff --git a/ui/res/drawable-xhdpi/ic_type_image.png b/ui/src/main/res/drawable-xhdpi/ic_type_image.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_image.png rename to ui/src/main/res/drawable-xhdpi/ic_type_image.png diff --git a/ui/res/drawable-xhdpi/ic_type_pdf.png b/ui/src/main/res/drawable-xhdpi/ic_type_pdf.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_pdf.png rename to ui/src/main/res/drawable-xhdpi/ic_type_pdf.png diff --git a/ui/res/drawable-xhdpi/ic_type_report.png b/ui/src/main/res/drawable-xhdpi/ic_type_report.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_report.png rename to ui/src/main/res/drawable-xhdpi/ic_type_report.png diff --git a/ui/res/drawable-xhdpi/ic_type_server_profile.png b/ui/src/main/res/drawable-xhdpi/ic_type_server_profile.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_server_profile.png rename to ui/src/main/res/drawable-xhdpi/ic_type_server_profile.png diff --git a/ui/res/drawable-xhdpi/ic_type_text.png b/ui/src/main/res/drawable-xhdpi/ic_type_text.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_text.png rename to ui/src/main/res/drawable-xhdpi/ic_type_text.png diff --git a/ui/res/drawable-xhdpi/ic_type_unknown.png b/ui/src/main/res/drawable-xhdpi/ic_type_unknown.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_unknown.png rename to ui/src/main/res/drawable-xhdpi/ic_type_unknown.png diff --git a/ui/res/drawable-xhdpi/ic_type_xls.png b/ui/src/main/res/drawable-xhdpi/ic_type_xls.png similarity index 100% rename from ui/res/drawable-xhdpi/ic_type_xls.png rename to ui/src/main/res/drawable-xhdpi/ic_type_xls.png diff --git a/ui/res/drawable/bs_white_blue.xml b/ui/src/main/res/drawable/bs_white_blue.xml similarity index 100% rename from ui/res/drawable/bs_white_blue.xml rename to ui/src/main/res/drawable/bs_white_blue.xml diff --git a/ui/res/drawable/gradient_light_grey.xml b/ui/src/main/res/drawable/gradient_light_grey.xml similarity index 100% rename from ui/res/drawable/gradient_light_grey.xml rename to ui/src/main/res/drawable/gradient_light_grey.xml diff --git a/ui/res/layout/file_list_item.xml b/ui/src/main/res/layout/file_list_item.xml similarity index 100% rename from ui/res/layout/file_list_item.xml rename to ui/src/main/res/layout/file_list_item.xml diff --git a/ui/res/layout/ic_boolean_layout.xml b/ui/src/main/res/layout/ic_boolean_layout.xml similarity index 100% rename from ui/res/layout/ic_boolean_layout.xml rename to ui/src/main/res/layout/ic_boolean_layout.xml diff --git a/ui/res/layout/ic_multi_select_layout.xml b/ui/src/main/res/layout/ic_multi_select_layout.xml similarity index 100% rename from ui/res/layout/ic_multi_select_layout.xml rename to ui/src/main/res/layout/ic_multi_select_layout.xml diff --git a/ui/res/layout/ic_single_select_layout.xml b/ui/src/main/res/layout/ic_single_select_layout.xml similarity index 100% rename from ui/res/layout/ic_single_select_layout.xml rename to ui/src/main/res/layout/ic_single_select_layout.xml diff --git a/ui/res/layout/ic_single_value_date_layout.xml b/ui/src/main/res/layout/ic_single_value_date_layout.xml similarity index 100% rename from ui/res/layout/ic_single_value_date_layout.xml rename to ui/src/main/res/layout/ic_single_value_date_layout.xml diff --git a/ui/res/layout/ic_single_value_layout.xml b/ui/src/main/res/layout/ic_single_value_layout.xml similarity index 100% rename from ui/res/layout/ic_single_value_layout.xml rename to ui/src/main/res/layout/ic_single_value_layout.xml diff --git a/ui/res/layout/resource_list_item.xml b/ui/src/main/res/layout/resource_list_item.xml similarity index 100% rename from ui/res/layout/resource_list_item.xml rename to ui/src/main/res/layout/resource_list_item.xml diff --git a/ui/src/main/res/layout/select_dialog_multichoice.xml b/ui/src/main/res/layout/select_dialog_multichoice.xml new file mode 100644 index 00000000..40034a85 --- /dev/null +++ b/ui/src/main/res/layout/select_dialog_multichoice.xml @@ -0,0 +1,31 @@ + + + + \ No newline at end of file diff --git a/ui/res/layout/server_profile_list_item.xml b/ui/src/main/res/layout/server_profile_list_item.xml similarity index 100% rename from ui/res/layout/server_profile_list_item.xml rename to ui/src/main/res/layout/server_profile_list_item.xml diff --git a/ui/res/layout/two_line_breadcrumbs.xml b/ui/src/main/res/layout/two_line_breadcrumbs.xml similarity index 100% rename from ui/res/layout/two_line_breadcrumbs.xml rename to ui/src/main/res/layout/two_line_breadcrumbs.xml diff --git a/ui/res/values/colors.xml b/ui/src/main/res/values/colors.xml similarity index 92% rename from ui/res/values/colors.xml rename to ui/src/main/res/values/colors.xml index 2ad043c8..3f16d15a 100644 --- a/ui/res/values/colors.xml +++ b/ui/src/main/res/values/colors.xml @@ -1,6 +1,6 @@ #333333 #7d7d7d - #c0c0c0 + #949494 #e7e7e7 #ff0000 diff --git a/ui/res/values/strings.xml b/ui/src/main/res/values/strings.xml similarity index 90% rename from ui/res/values/strings.xml rename to ui/src/main/res/values/strings.xml index bd62f620..89c37cec 100644 --- a/ui/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -26,6 +26,7 @@ - Uncheck All + Check all + Uncheck all diff --git a/ui/res/values/styles.xml b/ui/src/main/res/values/styles.xml similarity index 93% rename from ui/res/values/styles.xml rename to ui/src/main/res/values/styles.xml index 167ff1bc..0e962390 100644 --- a/ui/res/values/styles.xml +++ b/ui/src/main/res/values/styles.xml @@ -30,7 +30,7 @@ @@ -57,7 +57,7 @@ @@ -79,7 +79,7 @@ @@ -116,7 +116,7 @@ @@ -131,7 +131,7 @@ @@ -171,7 +171,7 @@ @drawable/gradient_light_grey center_vertical 45dp - fill_parent + match_parent