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();
}
}
Related
Hy,
I’m new to milo (and OPC-UA) and try to implement an OPC-UA server with Historical Data Access. I reused the current milo server example and create a history node. On this node I can query (with the Prosys OPC UA Client) the empty history. I know that I have to implement the persistency of the history nodes by myself.
So far so good – but I could not found any information about to handle the history read request and how to return the response. More precisely how to add the HistoryData to an HistoryReadResult
#Override
public void historyRead(HistoryReadContext context, HistoryReadDetails readDetails, TimestampsToReturn timestamps,
List<HistoryReadValueId> readValueIds)
{
List<HistoryReadResult> results = Lists.newArrayListWithCapacity(readValueIds.size());
for (HistoryReadValueId readValueId : readValueIds){
//return 3 historical entries
DataValue v1 = new DataValue(new Variant(new Double(1)), StatusCode.GOOD, new DateTime(Date.from(Instant.now().minus(1, ChronoUnit.MINUTES))));
DataValue v2 = new DataValue(new Variant(new Double(2)), StatusCode.GOOD, new DateTime(Date.from(Instant.now().minus(2, ChronoUnit.MINUTES))));
DataValue v3 = new DataValue(new Variant(new Double(3)), StatusCode.GOOD, new DateTime(Date.from(Instant.now().minus(3, ChronoUnit.MINUTES))));
HistoryData data = new HistoryData(new DataValue[] {v1,v2,v3});
//???
HistoryReadResult result = new HistoryReadResult(StatusCode.GOOD, ByteString.NULL_VALUE, ??? );
results.add(result);
}
context.complete(results);
}
You're going to need access to the spec to successfully implement historical access services. Part 4 and Part 11.
The last parameter in the HistoryReadResult constructor is supposed to be a HistoryData structure. ExtensionObject is basically the container that structures are encoded and transferred in.
To create that ExtensionObject you would first create a HistoryData (or HistoryModifiedData, depends... see the spec) and then do something like ExtensionObject.encode(historyData) to get the object you need to finish building the HistoryReadResult.
Overrides historyRead is the correct way to do.
HistoryReadResult result = new HistoryReadResult(StatusCode.GOOD, ByteString.NULL_VALUE,ExtensionObject.encode(data) );
However method was not called by generic client such as UA-Expert before defining my variableNode with specific AccessLevel and Historizing mode like this :
Set<AccessLevel> acclevels = new LinkedHashSet<>();
acclevels.add(AccessLevel.CurrentRead);
acclevels.add(AccessLevel.CurrentWrite);
acclevels.add(AccessLevel.HistoryRead);
UaVariableNode node = new UaVariableNode.UaVariableNodeBuilder(server.getNodeMap())
.setNodeId(new NodeId(namespaceIndex, "HelloWorld/Test/" + name))
.setAccessLevel(ubyte(AccessLevel.getMask(acclevels)))
.setUserAccessLevel(ubyte(AccessLevel.getMask(acclevels)))
.setBrowseName(new QualifiedName(namespaceIndex, name))
.setDisplayName(LocalizedText.english(name))
.setDataType(typeId)
.setTypeDefinition(Identifiers.BaseDataVariableType)
.setHistorizing(true)
.build();
I have a requirement to fetch the SenderName,SenderEmail,ToNames,ToEmails,CCNames,CcEmails from a lotus notes document instance.
Issue1
Looking into lotus.domino.Document API I found out the method getItems. When I write the elements to the system.out values for SenderEmail, ToEmails and CcEmails can be found.
However values for SenderName(a.k.a From), ToNames cannot be derived that easily.
The values seems to be using an common name format. For example check check my system.output below.
Principal = "CN=Amaw Scritz/O=fictive"
$MessageID = "<OF0FF3779B.36590F8A-ON80257D15.001DBC47-65257D15.001DC804#LocalDomain>"
INetFrom = "AmawScritz#fictive.com"
Recipients = "CN=Girl1/O=fictive#fictive"
MailOptions = "0"
SaveOptions = "1"
From = "CN=Amaw Scritz/O=fictive"
AltFrom = "CN=Amaw Scritz/O=fictive"
SendTo = "CN=Girl1/O=fictive#fictive"
CopyTo = "CN=Girl2/O=fictive#fictive"
BlindCopyTo = ""
InetSendTo = "Girl1#fictive.com"
InetCopyTo = "Girl2#fictive.com"
$Abstract = "sasdasda"
$UpdatedBy = "CN=Amaw Scritz/O=fictive"
Body = "Hello World"
The question is how can I get 'Amaw Scritz' from the common name 'CN=Amaw Scritz/O=fictive'. Is there any look up mechanism that can be used. (I would prefer to have a option other than doing a substring of the common name)
Issue2
is it possible to retrieve SentTime and ReceivedTime from mail document instance?
I know that there are two methods called getCreated and getLastModified. getCreated can be loosely associated with the SentTime and getLastModified can be loosely associated with ReceivedTime. Are there are other ways to get times for SentTime and ReceivedTime.
Issue3
How can one distinguish whether a mail document is a Sent mail or a Received Mail?
Issue1
You can use Name class.
Here example from this link:
import lotus.domino.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
// (Your code goes here)
// Create a hierarchical name
Name nam = session.createName(
"CN=John B Goode/OU=Sales/OU=East/O=Acme/C=US");
// Returns:
// John B Goode
// John B Goode/Sales/East/Acme/US
// CN=John B Goode/OU=Sales/OU=East/O=Acme/C=US
System.out.println(nam.getCommon());
System.out.println(nam.getAbbreviated());
System.out.println(nam.getCanonical());
} catch(Exception e) {
e.printStackTrace();
}
}
}
Issue2
Use values of PostedDate field and DeliveredDate field of mail document.
Issue3
Check that $Inbox folder contains your mail document. Or take a look at Dave Delay answer.
I agree with #nempoBu4 on Issues 1 and 2. I disagree with the answer to Issue 3. A received message can be removed from the inbox, so checking $Inbox doesn't help you distinguish between sent and received messages.
Assuming you have the document open, the best approach is to check two items. Sent and received messages both have a PostedDate item, but only a received message has a DeliveredDate item. Incidentally, a draft message has neither PostedDate or DeliveredDate.
I'm implementing a client to a web service (and the guys maintaining the web service have been a litte unresponsive..) I've used axis and WSDL2Java to generate java classes and I can call their login-method on their authentication-service ok, and get a sessionId back (eg z4zojhiqkw40lj55kgtn1oya). However, it seems that i cannot use this sessionId as a parameter anywhere. Even a call to their hasSession()-method directly after login returned false. I managed to solve this by setting setMaintainSession(true) on the Locator-object for this service. But the problem is, that this first service, the Authentication-service, is only used for authentification. If I then call setMaintainSession(true) on eg ProductServiceLocator, and call some method on it, I will get an error because of unauthenticated session. I have to find a way to share the session between the services on the client side.
Looking on their php code example-it seeems like they are storing the session in a cookie. How can I mimic this behaviour in my java client?
php-code:
$authentication = new SoapClient ( "https://webservices.24sevenoffice.com/authenticate/authenticate.asmx?wsdl", $options );
// log into 24SevenOffice if we don't have any active session. No point doing this more than once.
$login = true;
if (!empty($_SESSION['ASP.NET_SessionId'])){
$authentication->__setCookie("ASP.NET_SessionId", $_SESSION['ASP.NET_SessionId']);
try{
$login = !($authentication->HasSession()->HasSessionResult);
}
catch ( SoapFault $fault ) {
$login = true;
}
}
if( $login ){
$result = ($temp = $authentication->Login($params));
// set the session id for next time we call this page
$_SESSION['ASP.NET_SessionId'] = $result->LoginResult;
// each seperate webservice need the cookie set
$authentication->__setCookie("ASP.NET_SessionId", $_SESSION['ASP.NET_SessionId']);
// throw an error if the login is unsuccessful
if($authentication->HasSession()->HasSessionResult == false)
throw new SoapFault("0", "Invalid credential information.");
}
My code is the following:
AuthenticateLocator al = new AuthenticateLocator();
al.setMaintainSession(true);
Credential c = new Credential(CredentialType.Community,username,password,guid);
AuthenticateSoap s = al.getAuthenticateSoap();
String sessionId = s.login(c);
System.out.println("Session id was: "+sessionId);
System.out.println("Has Session: "+s.hasSession()); //Hooray, now works after setMaintainSession(true)
//And now trying to call another Service
CompanyServiceLocator cl = new CompanyServiceLocator();
cl.setMaintainSession(true);
CompanyServiceSoap css = cl.getCompanyServiceSoap();
css.getCountryList(); //FAILS!
So what can I do to make this work?
Hooray, I finally solved it myself :-D
Thanx a lot to the excellent article at http://www.nsftools.com/stubby/ApacheAxisClientTips.htm
I had to do the following with my code to make it work:
CompanyServiceLocator cl = new CompanyServiceLocator();
cl.setMaintainSession(true);
CompanyServiceSoap css = cl.getCompanyServiceSoap();
((Stub)css)._setProperty(HTTPConstants.HEADER_COOKIE, "ASP.NET_SessionId="+sessionId); //New line that does the magic
css.getCountryList(); //SUCCESS :-D
Operating in the high-level abstraction of the autogenerated classes, it was unknown to me that casting the service classes to Stub would expose more methods and properties that could be set. Good to know for later I guess :-)
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.
I am using Waffle for an SSO solution in my web-app.
Everything works fine but I would like to modify some functionality slightly:
Currently, if a user is not connected to the domain the SSO fails and opens a little authorization dialog:
The windows authorization requires the user name formatted like Domain\Username but most of my users will not know to add the domain in front of their username. So I would like to provide a default domain name if one is not specified.
I found a waffle function that I can override which will give me access to the decoded authentication token, I added a println to the waffle function and it shows the username in plain text (either with or without the domain depending on what is typed in the dialog):
public IWindowsSecurityContext acceptSecurityToken(String connectionId, byte[] token, String securityPackage) {
// I can see the passed username in the logs with this
System.out.println(new String(token));
// I don't understand any of the JNA stuff below this comment:
IWindowsCredentialsHandle serverCredential = new WindowsCredentialsHandleImpl(
null, Sspi.SECPKG_CRED_INBOUND, securityPackage);
serverCredential.initialize();
SecBufferDesc pbServerToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, Sspi.MAX_TOKEN_SIZE);
SecBufferDesc pbClientToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, token);
NativeLongByReference pfClientContextAttr = new NativeLongByReference();
CtxtHandle continueContext = _continueContexts.get(connectionId);
CtxtHandle phNewServerContext = new CtxtHandle();
int rc = Secur32.INSTANCE.AcceptSecurityContext(serverCredential.getHandle(),
continueContext, pbClientToken, new NativeLong(Sspi.ISC_REQ_CONNECTION),
new NativeLong(Sspi.SECURITY_NATIVE_DREP), phNewServerContext,
pbServerToken, pfClientContextAttr, null);
WindowsSecurityContextImpl sc = new WindowsSecurityContextImpl();
sc.setCredentialsHandle(serverCredential.getHandle());
sc.setSecurityPackage(securityPackage);
sc.setSecurityContext(phNewServerContext);
switch (rc)
{
case W32Errors.SEC_E_OK:
// the security context received from the client was accepted
_continueContexts.remove(connectionId);
// if an output token was generated by the function, it must be sent to the client process
if (pbServerToken != null
&& pbServerToken.pBuffers != null
&& pbServerToken.cBuffers.intValue() == 1
&& pbServerToken.pBuffers[0].cbBuffer.intValue() > 0) {
sc.setToken(pbServerToken.getBytes());
}
sc.setContinue(false);
break;
case W32Errors.SEC_I_CONTINUE_NEEDED:
// the server must send the output token to the client and wait for a returned token
_continueContexts.put(connectionId, phNewServerContext);
sc.setToken(pbServerToken.getBytes());
sc.setContinue(true);
break;
default:
sc.dispose();
WindowsSecurityContextImpl.dispose(continueContext);
_continueContexts.remove(connectionId);
throw new Win32Exception(rc);
}
return sc;
}
That whole function is from the Waffle API I only added the println at the beginning.
The passed username prints in plain text inside this token between a bunch of random byte chars (ÉsR=ÍtÍö?æ¸+Û-).
I am admittedly in very far over my head with JNA and java in general but I thought that because I can see the username here there must be a way to prepend the domain name to the username part of this token? I could be wrong.
My other idea was to add the domain to the pbClientToken that is created from the raw byte[] token this method is passed.
The pbClientToken is a JNA Structure object derivative. It has the Stucture method writeField which looked promising but I can't seem to figure out what field I should write. The Structure.getFields method doesn't seem to be available from pbClientToken.
I was hoping that this was a simple problem for someone more familiar with byte[] processing or JNA.
You cannot do this. What happens behind this dialog is a call to LogonUser on the user's machine, which gives you a ticket, which is then sent to the server. Unfortunately the server is not in the same domain, so even if you manage to extract the username it's completely useless.