Google Analytics authorization in java - java

I'm looking for the simplest way of programmatically logging in into Analytics and get data. Google documentation writes and gives examples for Oauth 2.0 which involves a user manually logging into with his google account, and then being redirected to my site with authorization. But this is not what I want to achieve - I'm building an automatic tool that needs to have user/pass or any other authorization key to be hard-coded and then log in without any user involvement (this is a periodic reporting tool).
I already found something about API KEY, but I can't find any example how to do that, or how to to that with Google java libraries.
I would be very grateful for pointing me into right direction. Also this may be valuable clue for others how to do it the simplest way - and I think logging should be simple.

I had the same problem and I took me about 1h to find this in the v3 documentation:
Service Accounts
Useful for automated/offline/scheduled access to Google Analytics data for your own account. For example, to build a live dashboard of your own Google Analytics data and share it with other users.
There are a few steps you need to follow to configure service accounts to work with Google Analytics:
Register a project in the APIs Console.
In the Google APIs Console, under the API Access pane, create a client ID with the Application Type set to Service Account.
Sign-in to Google Analytics and navigate to the Admin section.
Select the account for which you want the application to have access to.
Add the email address, from the Client ID created in the APIs Console from step #2, as a user of the selected Google Analytics account.
Follow the instructions for Service Accounts to access Google Analytics data.
Read more here:
https://developers.google.com/analytics/devguides/reporting/core/v3/gdataAuthorization
Puh, I guess the API is so big Google is having trouble documenting it an easy way =)
Then I looked at the code in the plus-serviceaccount-cmdline-sample and analytics-cmdline-sample. This is a very basic version implemented in a Playframework2 java app that
prints to System.out as the examples above:
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
public static Result index() {
GoogleCredential credential = null;
try {
credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("2363XXXXXXX#developer.gserviceaccount.com")
.setServiceAccountScopes(Arrays.asList(AnalyticsScopes.ANALYTICS_READONLY))
.setServiceAccountPrivateKeyFromP12File(new File("/your/path/to/privatekey/privatekey.p12"))
.build();
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Set up and return Google Analytics API client.
Analytics analytics = new Analytics.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(
"Google-Analytics-Hello-Analytics-API-Sample").build();
String profileId = "";
try {
profileId = getFirstProfileId(analytics);
} catch (IOException e) {
e.printStackTrace();
}
GaData gaData = null;
try {
gaData = executeDataQuery(analytics, profileId);
} catch (IOException e) {
e.printStackTrace();
}
printGaData(gaData);
return ok(index.render("Your new application is ready."));
}
private static String getFirstProfileId(Analytics analytics) throws IOException {
String profileId = null;
// Query accounts collection.
Accounts accounts = analytics.management().accounts().list().execute();
if (accounts.getItems().isEmpty()) {
System.err.println("No accounts found");
} else {
String firstAccountId = accounts.getItems().get(0).getId();
// Query webproperties collection.
Webproperties webproperties =
analytics.management().webproperties().list(firstAccountId).execute();
if (webproperties.getItems().isEmpty()) {
System.err.println("No Webproperties found");
} else {
String firstWebpropertyId = webproperties.getItems().get(0).getId();
// Query profiles collection.
Profiles profiles =
analytics.management().profiles().list(firstAccountId, firstWebpropertyId).execute();
if (profiles.getItems().isEmpty()) {
System.err.println("No profiles found");
} else {
profileId = profiles.getItems().get(0).getId();
}
}
}
return profileId;
}
/**
* Returns the top 25 organic search keywords and traffic source by visits. The Core Reporting API
* is used to retrieve this data.
*
* #param analytics the analytics service object used to access the API.
* #param profileId the profile ID from which to retrieve data.
* #return the response from the API.
* #throws IOException tf an API error occured.
*/
private static GaData executeDataQuery(Analytics analytics, String profileId) throws IOException {
return analytics.data().ga().get("ga:" + profileId, // Table Id. ga: + profile id.
"2012-01-01", // Start date.
"2012-01-14", // End date.
"ga:visits") // Metrics.
.setDimensions("ga:source,ga:keyword")
.setSort("-ga:visits,ga:source")
.setFilters("ga:medium==organic")
.setMaxResults(25)
.execute();
}
/**
* Prints the output from the Core Reporting API. The profile name is printed along with each
* column name and all the data in the rows.
*
* #param results data returned from the Core Reporting API.
*/
private static void printGaData(GaData results) {
System.out.println("printing results for profile: " + results.getProfileInfo().getProfileName());
if (results.getRows() == null || results.getRows().isEmpty()) {
System.out.println("No results Found.");
} else {
// Print column headers.
for (GaData.ColumnHeaders header : results.getColumnHeaders()) {
System.out.printf("%30s", header.getName());
}
System.out.println();
// Print actual data.
for (List<String> row : results.getRows()) {
for (String column : row) {
System.out.printf("%30s", column);
}
System.out.println();
}
System.out.println();
}
}
Hope this helps!

I solved it finally with the 2.4 version of Core Reporting - there's autorization with your gmail user/pass, just as simple as it should be - I wonder why there's no example how to do this in new 3.0 version.
Core reporting 2.4: http://code.google.com/intl/pl-PL/apis/analytics/docs/gdata/v2/gdataJava.html

I attempted to follow the example provided and it does not compile. I don't know if this is 3.0 vs 2.4 and if so, is there a way that the example code can be made to work -- proper choice of jars or what.
One problem with the example is that the argument to setServiceAccountScopes is no longer a string but a Collections.singleton(AnalyticsScopes.Analytics.READ_ONLY).
Also important to using the example is proper configuration of the Service Account.

As an answer to another question I wrote a code example in Java which works for me.
See:
https://stackoverflow.com/a/24043488/1391050

Related

Amazon DynamoDB taking long time to fetch record with high latency up to 5-6 second

pom.xml
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-bom</artifactId>
<version>1.11.256</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
</dependency>
Client Code
public static AmazonDynamoDB getDynamoDBClient() {
return AmazonDynamoDBClientBuilder.standard().withRegion("ap-southeast-1").build();
}
Now i am trying to execute a normal query having few records but it is taking long time to fetch the result.
For first time it is fetching the records in around 5-6 seconds on multiple requests in reduces by half. 2-3 seconds is still large time for fetching only few items.
Already checked the tuning of dynamo DB using different client configurations (connection timeout, request timeout, retry etc.) but not giving results as expected.
Also checked with SDK version 2 URLConnectionHTTPClient config but same results came there too.
One possible cause can be the credentials fetch time for dynamo DB client but not having any credentials caching reference in java. Can any one suggest possible configuration to improve this latency.
You are using a very old API and is not best practice anymore. To use best practice with Java, use the AWS SDK for Java v2.
The AWS SDK for Java 2.x is a major rewrite of the version 1.x code base. It’s built on top of Java 8+ and adds several frequently requested features. These include support for non-blocking I/O and the ability to plug in a different HTTP implementation at run time.
The POM for v2 is:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.17.190</version>
<type>pom</type>
<scope>import</scope>
</dependency>
To retrieve records using the AWS SDK for Java v2, you have three choices.
Use the DynamoDbClient.
Use the Enhanced Client (that maps Java objects to tables)
Use PartiQL (uses SQL like syntax)
I will show you all ways. All examples can be found in the Amazon Github repo.
Use the DynamoDbClient
Code is:
package com.example.dynamodb;
// snippet-start:[dynamodb.java2.get_item.import]
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
// snippet-end:[dynamodb.java2.get_item.import]
/**
* Before running this Java V2 code example, set up your development environment, including your credentials.
*
* For more information, see the following documentation topic:
*
* https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
*
* To get an item from an Amazon DynamoDB table using the AWS SDK for Java V2, its better practice to use the
* Enhanced Client, see the EnhancedGetItem example.
*/
public class GetItem {
public static void main(String[] args) {
final String usage = "\n" +
"Usage:\n" +
" <tableName> <key> <keyVal>\n\n" +
"Where:\n" +
" tableName - The Amazon DynamoDB table from which an item is retrieved (for example, Music3). \n" +
" key - The key used in the Amazon DynamoDB table (for example, Artist). \n" +
" keyval - The key value that represents the item to get (for example, Famous Band).\n" ;
if (args.length != 3) {
System.out.println(usage);
System.exit(1);
}
String tableName = "Customer" ; //args[0];
String key = "id" ; //args[1];
String keyVal = "id101" ; //args[2];
System.out.format("Retrieving item \"%s\" from \"%s\"\n", keyVal, tableName);
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_EAST_1;
DynamoDbClient ddb = DynamoDbClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.build();
getDynamoDBItem(ddb, tableName, key, keyVal);
ddb.close();
}
// snippet-start:[dynamodb.java2.get_item.main]
public static void getDynamoDBItem(DynamoDbClient ddb,String tableName,String key,String keyVal ) {
HashMap<String,AttributeValue> keyToGet = new HashMap<>();
keyToGet.put(key, AttributeValue.builder()
.s(keyVal).build());
GetItemRequest request = GetItemRequest.builder()
.key(keyToGet)
.tableName(tableName)
.build();
try {
Map<String,AttributeValue> returnedItem = ddb.getItem(request).item();
if (returnedItem != null) {
Set<String> keys = returnedItem.keySet();
System.out.println("Amazon DynamoDB table attributes: \n");
for (String key1 : keys) {
System.out.format("%s: %s\n", key1, returnedItem.get(key1).toString());
}
} else {
System.out.format("No item found with the key %s!\n", key);
}
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
// snippet-end:[dynamodb.java2.get_item.main]
}
Enhanced Client
Code is:
package com.example.dynamodb;
// snippet-start:[dynamodb.java2.mapping.getitem.import]
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
// snippet-end:[dynamodb.java2.mapping.getitem.import]
/*
* Before running this code example, create an Amazon DynamoDB table named Customer with these columns:
* - id - the id of the record that is the key
* - custName - the customer name
* - email - the email value
* - registrationDate - an instant value when the item was added to the table
*
* Also, ensure that you have set up your development environment, including your credentials.
*
* For information, see this documentation topic:
*
* https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
*/
public class EnhancedGetItem {
public static void main(String[] args) {
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_EAST_1;
DynamoDbClient ddb = DynamoDbClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
getItem(enhancedClient);
ddb.close();
}
// snippet-start:[dynamodb.java2.mapping.getitem.main]
public static void getItem(DynamoDbEnhancedClient enhancedClient) {
try {
DynamoDbTable<Customer> table = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
Key key = Key.builder()
.partitionValue("id120")
.build();
// Get the item by using the key.
Customer result = table.getItem(r->r.key(key));
System.out.println("******* The description value is "+result.getCustName());
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
// snippet-end:[dynamodb.java2.mapping.getitem.main]
}
PartiQL
Code is
public static void getItem(DynamoDbClient ddb) {
String sqlStatement = "SELECT * FROM MoviesPartiQ where year=? and title=?";
List<AttributeValue> parameters = new ArrayList<>();
AttributeValue att1 = AttributeValue.builder()
.n("2012")
.build();
AttributeValue att2 = AttributeValue.builder()
.s("The Perks of Being a Wallflower")
.build();
parameters.add(att1);
parameters.add(att2);
try {
ExecuteStatementResponse response = executeStatementRequest(ddb, sqlStatement, parameters);
System.out.println("ExecuteStatement successful: "+ response.toString());
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
All of these ways are recommend using over AWS SDK for Java V1. If you are not familiar with the V2 API - including creds and setting up your dev environment, see:
Developer guide - AWS SDK for Java 2.x
For first time it is fetching the records in around 5-6 seconds on multiple requests in reduces by half. 2-3 seconds is still large time for fetching only few items.
This is expected even with dynamo at production because first time you fetch the following sequence of operations happens:-
Look up for the partition ID your requested data belongs to from the route table.
Caches the Key to Partiton
Then refers to the partition for fetching the data.
As you see there is caching in step 2, so the next time requests go, the partition id is fetched from the cache thus the latency decreases. (will share the source once I have it)
Can any one suggest possible configuration to improve this latency.
Also, please don't use local dynamo for performance benchmarking, because it internally uses SQLite, i.e. SQL DB for storing.
refer:- https://www.dbi-services.com/blog/aws-dynamodb-local/#:~:text=Yes%2C%20this%20NoSQL%20database%20is,Local%20engine%2C%20embedded%20in%20Java.

Unable to validate google recaptcha enterprise. getting error: java.io.IOException: The Application Default Credentials are not available

Unable to validate google recaptcha enterprise. getting error:
java.io.IOException: The Application Default Credentials are not available.
java.io.IOException: The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials.
I have also created credential json with service account and set in environment variable GOOGLE_APPLICATION_CREDENTIALS and alternatively created credential json with aws external account and set in environment variable. but "I was getting required parameters" must be specified error
Note: I am able to get the token from client side but this error is from server side.
Code blocks used to get credentials:
Method1 :
// If you don't specify credentials when constructing the client, the client library will
// look for credentials via the environment variable GOOGLE_APPLICATION_CREDENTIALS.
Storage storage = StorageOptions.getDefaultInstance().getService();
System.out.println("Buckets:");
Page<Bucket> buckets = storage.list();
for (Bucket bucket : buckets.iterateAll()) {
System.out.println(bucket.toString());
}
Method2:
System.setProperty("GOOGLE_APPLICATION_CREDENTIALS", jsonPath);
System.out.println("GOOGLE_APPLICATION_CREDENTIALS");
System.out.println(System.getProperty("GOOGLE_APPLICATION_CREDENTIALS"));
FileInputStream fileInputStream = new FileInputStream(jsonPath);
GoogleCredentials credentials = GoogleCredentials.fromStream(fileInputStream)
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();
System.out.println("Buckets:");
Page<Bucket> buckets = storage.list();
for (Bucket bucket : buckets.iterateAll()) {
System.out.println(bucket.toString());
}
Interpreting assesment:
/**
* Create an assessment to analyze the risk of an UI action.
*
* #param projectID: GCloud Project ID
* #param recaptchaSiteKey: Site key obtained by registering a domain/app to use recaptcha services.
* #param token: The token obtained from the client on passing the recaptchaSiteKey.
* #param recaptchaAction: Action name corresponding to the token.
*/
public static void createAssessment(String projectID, String recaptchaSiteKey, String token,
String recaptchaAction)
throws IOException {
// Initialize a client that will be used to send requests. This client needs to be created only
// once, and can be reused for multiple requests. After completing all of your requests, call
// the `client.close()` method on the client to safely
// clean up any remaining background resources.
try (RecaptchaEnterpriseServiceClient client = RecaptchaEnterpriseServiceClient.create()) {
// Specify a name for this assessment.
String assessmentName = "assessment-name";
// Set the properties of the event to be tracked.
Event event = Event.newBuilder()
.setSiteKey(recaptchaSiteKey)
.setToken(token)
.build();
// Build the assessment request.
CreateAssessmentRequest createAssessmentRequest = CreateAssessmentRequest.newBuilder()
.setParent(ProjectName.of(projectID).toString())
.setAssessment(Assessment.newBuilder().setEvent(event).setName(assessmentName).build())
.build();
Assessment response = client.createAssessment(createAssessmentRequest);
// Check if the token is valid.
if (!response.getTokenProperties().getValid()) {
System.out.println("The CreateAssessment call failed because the token was: " +
response.getTokenProperties().getInvalidReason().name());
return;
}
// Check if the expected action was executed.
if (!response.getTokenProperties().getAction().equals(recaptchaAction)) {
System.out.println("The action attribute in your reCAPTCHA tag " +
"does not match the action you are expecting to score");
return;
}
// Get the risk score and the reason(s).
// For more information on interpreting the assessment,
// see: https://cloud.google.com/recaptcha-enterprise/docs/interpret-assessment
float recaptchaScore = response.getRiskAnalysis().getScore();
System.out.println("The reCAPTCHA score is: " + recaptchaScore);
for (ClassificationReason reason : response.getRiskAnalysis().getReasonsList()) {
System.out.println(reason);
}
}
I was able to acheive the same using recaptcha V3 instead of enterprise version. As we had to acheive scored based assesment , V3 supports score based validation.

AWS SDK - WAF & Lambda integration for updating an IP Set List

Currently trying to create a slack slash command that triggers an AWS Lambda function. That part is simple enough and is integrated. The lambda function is then supposed to access a specific WAF, grab the IP Set List, and insert an IP address into this list. Essentially, adding a remote IP address to a whitelist, so that remote developers can work on the web development of a website from outside of the firewall.
The problem that I have been having is that I cannot seem to get the AWS - SDK to function properly (obviously my fault haha). I have tried using the SDK to implement my solution in both Java and NodeJS, but have run into two different problems.
JAVA IMPLEMENTATION
The main problem with this code is that after executing the code, nothing is added to my ACL whitelist inside of my WAF.
The code runs in Eclipse. All dependencies should be set up in the environment. Code is being run from the Eclipse environment itself, instead of being triggered from the aws lambda console. Run as so:
eclipse console screen shot. The code executes and interacts with the aws sdk. At first, I thought that my code lambda code was incaple of interacting with my AWS account unless the lambda code was deployed and triggered. However, I created some code with the java aws-sdk (in the same function) that creates an S3 bucket.
public class LambdaFunctionHandler implements RequestHandler<S3Event, Object> {
#Override
public String handleRequest(S3Event input, Context context) {
String return_object = "Hello, " + input + "!";
System.out.println("hello again");
try {
createWAF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO: implement your handler
return return_object;
}
public void createWAF() throws IOException {
AWSCredentials credentials = null; // real credentials are passed in non-example code
/*
* AWSWAF is an interface. To construct an waf object with access to waf service methods you must
* invoke the constructor of AWSWAF--Client
* pass the credentails as an argument in order to have access to specified AWS account
*/
AWSWAF waf = new AWSWAFClient(credentials);
/*
* When you want to create, update, or delete AWS WAF objects, get a change token and include the change
* token in the create, update, or delete request.
* Change tokens ensure that your application doesn't submit conflicting requests to AWS WAF.
*
*/
GetChangeTokenResult changeToken = null;
try {
System.out.println("change token is converted to PENDING status");
changeToken = waf.getChangeToken(new GetChangeTokenRequest());
System.out.println(changeToken.toString());
} catch (WAFInternalErrorException exception){
System.out.println("error when initializing ChangeToken param");
System.out.println(exception.getErrorMessage());
}
GetIPSetRequest request = new GetIPSetRequest();
request.setIPSetId(IPSetId);
System.out.println("before updating ip set");
System.out.println(waf.getIPSet(request));
try{
/*
* AWS updateIPSetResult() method states that to create and configure an IPSet, perform the following steps:
* 1. Submit a CreateIPSet request.
* 2. Use GetChangeToken to get the change token that you provide in the ChangeToken parameter of an UpdateIPSet
* request.
* 3. Submit an UpdateIPSet request to specify the IP addresses that you want AWS WAF to watch for.
*/
/*
* if IP list is already created inside of an ACL - WAF, do you really need to create a new IP set?
* CreateIPSetRequest createipsetrequest = new CreateIPSetRequest();
* createipsetrequest.setName("NewIPSet");
* createipsetrequest.setChangeToken(changeToken.toString());
* CreateIPSetResult createipset = waf.createIPSet(createipsetrequest);
*/
/*
* Must pass a list of parameters to our updateIPSet() call, which includes:
* 1. a changeToken with empty parameters
* 2. the id of the ip set that we want to update
* 3. a collection of IPSetUpdates, which includes
* A) set action -- INSERT IN THIS CASE
* B) set type -- IPV4
* C) value -- ip address we want to update (arbitrary in this case)
*/
UpdateIPSetRequest updateParams = new UpdateIPSetRequest();
updateParams.setChangeToken(changeToken.toString());
updateParams.setIPSetId(IPSetId); // param exists - redacted in here
Collection<IPSetUpdate> ipToAdd = new ArrayList<IPSetUpdate>();
IPSetUpdate howToUpdateIPList = new IPSetUpdate();
howToUpdateIPList.setAction(ChangeAction.INSERT);
IPSetDescriptor ipsetdescriptor = new IPSetDescriptor();
ipsetdescriptor.setType(IPSetDescriptorType.IPV4);
ipsetdescriptor.setValue("192.0.2.44/32");
howToUpdateIPList.setIPSetDescriptor(ipsetdescriptor);
ipToAdd.add(howToUpdateIPList);
updateParams.setUpdates(ipToAdd);
System.out.println("Result: ");
UpdateIPSetResult result = waf.updateIPSet(updateParams);
System.out.println(result);
} catch (WAFStaleDataException | WAFInternalErrorException e) {
//exception handling done here
}
System.out.println("after updating ip set");
request.setIPSetId(IPSetId);
System.out.println(waf.getIPSet(request));
}
I will add the NodeJS questions to a separate thread. Thank you for reading this far. I appreciate your time, and any help you can offer.

How to program availability check and to create new meeting to Outlook?

I am creating a Java web app to manage meetings between a set of students and teachers. All of them already use Outlook to manage their email and personal calendar.
I would like to know if it's even possible to build the schedule feature of my web app using Exchange, Office365 or Sharepoint Team Calendar via REST service in order to check the availability and create a meeting for a student and one of the teachers available:
SharePoint 2013 REST service
So far, the most promising mechanism I have found is Microsoft Sharepoint Server's calendar, which collaborative features makes possible to create a meeting and check availability for a list of users. The downside is that it does not support one to one meetings but for the entire team (as far I have found).
My second option would be to require everyone in the group (students and teachers of the department) to make public their personal calendar so the web app be able to check the availability of both student and teacher and send a meeting request. The obvious problem is the privacy/security concern derived from this approach.
My last option (and by far the less favourite because it feels like re-inventing the wheel) is to build a proprietary calendar within the web app and send iCal requests to each person. The obvious problem with this approach is synchronisation between the two separated calendars.
In addition, this feature must be a pretty common need so there should be tons of blogs explaining how to take advantage of Exchange/Sharepoint/Office365 to implement it (other platforms are not considered since my employer's infrastructure is based on Microsoft). However, whether it is so obvious that nobody talks about it or I have not searched in the right place. Any advice to point me in the right direction?
Exchange natively shows user calendar availability exposed in EWS (Exchange Web Services), your network administrator must configure Exchange server enabling EWS.
But guess what... Office 365 (as I know) have EWS services enabled, due exchange is part of office 365 offer.
As EWS are normal Web services you should create a "service stub" or proxy in whatever you use in java to create services references mapping wsdl files.
Exchanged EWS is my preferred solution.
Hope this helps.
This is the reference page, this link show how to use the service references from C# to make the right API calls.
http://msdn.microsoft.com/en-us/library/exchange/aa494212(v=exchg.140).aspx
static void GetUserAvailability(ExchangeServiceBinding esb)
{
// Identify the time to compare free/busy information.
Duration duration = new Duration();
duration.StartTime = DateTime.Now;
duration.EndTime = DateTime.Now.AddHours(4);
// Identify the options for comparing free/busy information.
FreeBusyViewOptionsType fbViewOptions = new FreeBusyViewOptionsType();
fbViewOptions.TimeWindow = duration;
fbViewOptions.RequestedView = FreeBusyViewType.MergedOnly;
fbViewOptions.RequestedViewSpecified = true;
fbViewOptions.MergedFreeBusyIntervalInMinutes = 35;
fbViewOptions.MergedFreeBusyIntervalInMinutesSpecified = true;
MailboxData[] mailboxes = new MailboxData[1];
mailboxes[0] = new MailboxData();
// Identify the user mailbox to review for free/busy data.
EmailAddress emailAddress = new EmailAddress();
emailAddress.Address = "tplate#contoso.com";
emailAddress.Name = String.Empty;
mailboxes[0].Email = emailAddress;
mailboxes[0].ExcludeConflicts = false;
// Make the request.
GetUserAvailabilityRequestType request = new GetUserAvailabilityRequestType();
// Set the time zone of the request.
request.TimeZone = new SerializableTimeZone();
request.TimeZone.Bias = 480;
request.TimeZone.StandardTime = new SerializableTimeZoneTime();
request.TimeZone.StandardTime.Bias = 0;
request.TimeZone.StandardTime.DayOfWeek = DayOfWeekType.Sunday.ToString();
request.TimeZone.StandardTime.DayOrder = 1;
request.TimeZone.StandardTime.Month = 11;
request.TimeZone.StandardTime.Time = "02:00:00";
request.TimeZone.DaylightTime = new SerializableTimeZoneTime();
request.TimeZone.DaylightTime.Bias = -60;
request.TimeZone.DaylightTime.DayOfWeek = DayOfWeekType.Sunday.ToString();
request.TimeZone.DaylightTime.DayOrder = 2;
request.TimeZone.DaylightTime.Month = 3;
request.TimeZone.DaylightTime.Time = "02:00:00";
// Add the mailboxes to the request.
request.MailboxDataArray = mailboxes;
// Add the view options to the request.
request.FreeBusyViewOptions = fbViewOptions;
try
{
// Send the request and get the response.
GetUserAvailabilityResponseType response = esb.GetUserAvailability(request);
// Access free/busy information.
if (response.FreeBusyResponseArray.Length < 1)
{
throw new Exception("No free/busy response data available.");
}
else
{
foreach (FreeBusyResponseType fbrt in response.FreeBusyResponseArray)
{
if (fbrt.ResponseMessage.ResponseClass == ResponseClassType.Error)
{
Console.WriteLine(string.Format("Error: {0}", fbrt.ResponseMessage.MessageText));
}
else
{
// Show the free/busy stream.
FreeBusyView fbv = fbrt.FreeBusyView;
Console.WriteLine(string.Format("Merged free/busy data: {0}", fbv.MergedFreeBusy));
}
}
}
}
catch (Exception e)
{
// Perform error processing.
Console.WriteLine(e.Message);
Console.ReadLine();
}
}

Calling Microsoft Dynamics CRM 2011 online from JAVA

I'm doing a Dynamics CRM integration from a Java application and I've followed the example from the CRM training kit and managed successfully to connect and create accounts and contacts.
Now I'm having some problems with adding some more fields in the account creation and when connecting a contact with an account.
For instance I cannot create accounts with "address1_freighttermscode" that is a picklist.
My code is the following:
private static OrganizationServiceStub.Guid createAccount(OrganizationServiceStub serviceStub, String[] args) {
try {
OrganizationServiceStub.Create entry = new OrganizationServiceStub.Create();
OrganizationServiceStub.Entity newEntryInfo = new OrganizationServiceStub.Entity();
OrganizationServiceStub.AttributeCollection collection = new OrganizationServiceStub.AttributeCollection();
if (! (args[0].equals("null") )) {
OrganizationServiceStub.KeyValuePairOfstringanyType values = new OrganizationServiceStub.KeyValuePairOfstringanyType();
values.setKey("name");
values.setValue(args[0]);
collection.addKeyValuePairOfstringanyType(values);
}
if (! (args[13].equals("null"))){
OrganizationServiceStub.KeyValuePairOfstringanyType incoterm = new OrganizationServiceStub.KeyValuePairOfstringanyType();
incoterm.setKey("address1_freighttermscode");
incoterm.setValue(args[13]);
collection.addKeyValuePairOfstringanyType(incoterm);
}
newEntryInfo.setAttributes(collection);
newEntryInfo.setLogicalName("account");
entry.setEntity(newEntryInfo);
OrganizationServiceStub.CreateResponse createResponse = serviceStub.create(entry);
OrganizationServiceStub.Guid createResultGuid = createResponse.getCreateResult();
System.out.println("New Account GUID: " + createResultGuid.getGuid());
return createResultGuid;
} catch (IOrganizationService_Create_OrganizationServiceFaultFault_FaultMessage e) {
logger.error(e.getMessage());
} catch (RemoteException e) {
logger.error(e.getMessage());
}
return null;
}
When it executes, I get this error
[ERROR] Incorrect attribute value type System.String
Does anyone have examples on how to handle picklists or lookups?
To connect the contact with the account I'm filling the fields parentcustomerid and parentcustomeridtype with the GUID from the account and with "account", but the contact does not get associated with the account.
To set a picklist value you must use an OptionSet and for a lookup you must use an EntityReference. See the SDK's C# documentation, should work the same way using the Axis generated Java code.
incoterm.setKey("address1_freighttermscode")
//assuming the arg is an integer value that matches a picklist value for the attribute
OptionSetValue freight = new OptionSetValue();
freight.Value = args[13];
incoterm.setValue(freight);
collection.addKeyValuePairOfstringanyType(incoterm);
I haven't worked with Java for over a decade (and never towards an MS creation like Dynamics) so it might be way off from what you like. :)
You could use the REST web service and call directly to CRM creating your instances. As far I know, that's platform independent and should work as long as you can connect to the exposed service OrganizationData.

Categories