/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2013 ForgeRock AS. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://forgerock.org/license/CDDLv1.0.html
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at http://forgerock.org/license/CDDLv1.0.html
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*/
package org.forgerock.openicf.connectors.webtimesheet;
import java.util.*;
import org.identityconnectors.common.security.*;
import org.identityconnectors.framework.spi.*;
import org.identityconnectors.framework.spi.operations.*;
import org.identityconnectors.framework.common.objects.*;
import org.identityconnectors.framework.common.objects.filter.FilterTranslator;
import org.identityconnectors.common.logging.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Main implementation of the WebTimeSheet Connector
*
* @author Robert Jackson - <a href='http://www.nulli.com'>Nulli</a>
*/
@ConnectorClass(
displayNameKey = "WebTimeSheet",
configurationClass = WebTimeSheetConfiguration.class)
public class WebTimeSheetConnector implements PoolableConnector, CreateOp, UpdateOp, DeleteOp, SchemaOp, SearchOp<String>, TestOp {
public static final java.lang.String ATTR_LAST_NAME = "LastName";
public static final java.lang.String ATTR_FIRST_NAME = "FirstName";
public static final java.lang.String ATTR_LOGIN_NAME = "LoginName";
public static final java.lang.String ATTR_ID = "Id";
public static final java.lang.String ATTR_EMPLOYEE_ID = "EmployeeId";
public static final java.lang.String ATTR_INTERNAL_EMAIL = "Email";
public static final java.lang.String ATTR_PARENT_ID = "ParentDepartmentId";
public static final java.lang.String ATTR_DEPARTMENT = "DepartmentId";
public static final java.lang.String ATTR_DOMAIN = "Domain";
public static final java.lang.String ATTR_AUTH_TYPE = "AuthenticationType";
public static final java.lang.String OBCLASS_DEPARTMENT_NAME = "Department";
/**
* Setup logging for the {@link WebTimeSheetConnector}.
*/
private static final Log log = Log.getLog(WebTimeSheetConnector.class);
/**
* Place holder for the Connection created in the init method
*/
private RepliConnectClient connection;
/**
* Place holder for the {@link Configuration} passed into the init() method
* {@link WebTimeSheetConnector#init}.
*/
private WebTimeSheetConfiguration config;
/**
* Gets the Configuration context for this connector.
*/
public Configuration getConfiguration() {
return this.config;
}
/**
* Callback method to receive the {@link Configuration}.
*
* @see Connector#init
*/
public void init(Configuration cfg) {
this.config = (WebTimeSheetConfiguration) cfg;
this.connection = new RepliConnectClient(this.config);
}
/**
* Disposes of the {@link WebTimeSheetConnector}'s resources.
*
* @see Connector#dispose()
*/
public void dispose() {
config = null;
if (connection != null) {
connection.dispose();
connection = null;
}
}
public void checkAlive() {
connection.testConnection();
}
/**
* ****************
* SPI Operations
*
* Implement the following operations using the contract and description
* found in the Javadoc for these methods.
*****************
*/
/**
* {@inheritDoc}
*/
public Uid create(final ObjectClass objClass, final Set<Attribute> attrs, final OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objClass)) {
return connection.createUser(attrs, "1");
} else if (objClass.is(OBCLASS_DEPARTMENT_NAME)) {
throw new IllegalArgumentException("Creation of Departments not yet implemented");
} else {
throw new IllegalArgumentException("Unsupported objectclass '" + objClass + "'");
}
}
/**
* {@inheritDoc}
*/
public void delete(final ObjectClass objClass, final Uid uid, final OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objClass)) {
connection.deleteUser(uid.getUidValue());
} else if (objClass.is(OBCLASS_DEPARTMENT_NAME)) {
throw new IllegalArgumentException("Deletions of Departments not yet implemented");
} else {
throw new IllegalArgumentException("Unsupported objectclass '" + objClass + "'");
}
}
/**
* {@inheritDoc}
*/
public Schema schema() {
SchemaBuilder schemaBuilder = new SchemaBuilder(getClass());
Set<AttributeInfo> attributes = new HashSet<AttributeInfo>();
//User Objects
// Required Attributes
//
AttributeInfoBuilder aib = new AttributeInfoBuilder();
//aib.setCreateable(true);
aib.setUpdateable(false);
aib.setName(Name.NAME);
attributes.add(aib.build());
aib.setName(ATTR_ID);
attributes.add(aib.build());
// regular attributes
//
attributes.add(AttributeInfoBuilder.build(ATTR_LAST_NAME));
attributes.add(AttributeInfoBuilder.build(ATTR_FIRST_NAME));
attributes.add(AttributeInfoBuilder.build(ATTR_LOGIN_NAME));
attributes.add(AttributeInfoBuilder.build(ATTR_DEPARTMENT));
attributes.add(AttributeInfoBuilder.build(ATTR_EMPLOYEE_ID));
attributes.add(AttributeInfoBuilder.build(ATTR_INTERNAL_EMAIL));
attributes.add(AttributeInfoBuilder.build(ATTR_DOMAIN));
attributes.add(AttributeInfoBuilder.build(ATTR_AUTH_TYPE));
// Operational attributes
//
attributes.add(OperationalAttributeInfos.PASSWORD);
attributes.add(OperationalAttributeInfos.ENABLE);
schemaBuilder.defineObjectClass(ObjectClass.ACCOUNT_NAME, attributes);
// Department objects
//
ObjectClassInfoBuilder oib = new ObjectClassInfoBuilder();
oib.setContainer(true);
oib.setType(OBCLASS_DEPARTMENT_NAME);
oib.addAttributeInfo(new AttributeInfoBuilder().setUpdateable(false).setName(Name.NAME).build());
oib.addAttributeInfo(new AttributeInfoBuilder().setUpdateable(false).setName(ATTR_ID).build());
oib.addAttributeInfo(new AttributeInfoBuilder().setUpdateable(false).setName(ATTR_PARENT_ID).build());
final ObjectClassInfo department = oib.build();
schemaBuilder.defineObjectClass(department);
schemaBuilder.removeSupportedObjectClass(CreateOp.class, department);
schemaBuilder.removeSupportedObjectClass(DeleteOp.class, department);
schemaBuilder.removeSupportedObjectClass(SearchOp.class, department);
schemaBuilder.removeSupportedObjectClass(UpdateOp.class, department);
return schemaBuilder.build();
}
public FilterTranslator<String> createFilterTranslator(ObjectClass objClass, OperationOptions options) {
return new WebTimeSheetFilterTranslator();
}
/**
* {@inheritDoc}
*/
public void executeQuery(ObjectClass objClass, String query, ResultsHandler handler, OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objClass)) {
JSONObject response;
if (query == null) {
response = connection.listUsers(query);
} else {
response = connection.getUser(query);
}
try {
JSONArray users = response.getJSONArray("Value");
for (int a = 0; a < users.length(); a++) {
this.buildUser(users.getJSONObject(a), handler);
}
}
catch (JSONException ex) {
}
/* } else if (objClass.is(OBCLASS_DEPARTMENT_NAME)) {
String parent = null;
if (options.getContainer() != null) {
parent = options.getContainer().getUid().getUidValue();
}
NodeList depts = connection.getClient().listDepartments(query, options.getScope(), parent);
log.info("{0} Departments Returned", depts.getLength());
for (int a = 0; a < depts.getLength(); a++) {
this.buildDepartment(depts.item(a), handler);
}
*/
} else {
throw new IllegalArgumentException("Unsupported objectclass '" + objClass + "'");
}
}
/* public void executeQuery(ObjectClass objClass, String query, ResultsHandler handler, OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objClass)) {
NodeList users = connection.getClient().listUsers(query);
log.info("{0} Users Returned", users.getLength());
for (int a = 0; a < users.getLength(); a++) {
this.buildUser(users.item(a), handler);
}
} else if (objClass.is(OBCLASS_DEPARTMENT_NAME)) {
String parent = null;
if (options.getContainer() != null) {
parent = options.getContainer().getUid().getUidValue();
}
NodeList depts = connection.getClient().listDepartments(query, options.getScope(), parent);
log.info("{0} Departments Returned", depts.getLength());
for (int a = 0; a < depts.getLength(); a++) {
this.buildDepartment(depts.item(a), handler);
}
} else {
throw new IllegalArgumentException("Unsupported objectclass '" + objClass + "'");
}
throw new IllegalArgumentException("Unsupported objectclass '" + objClass + "'");
}*/
/**
* {@inheritDoc}
*/
public Uid update(ObjectClass objclass,
Uid uid,
Set<Attribute> replaceAttributes,
OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objclass)) {
return connection.updateUser(uid.getUidValue(), replaceAttributes);
}
/*else if (objclass.is(OBCLASS_DEPARTMENT_NAME)) {
throw new IllegalArgumentException("Modifications to Departments not yet implimented");
} */
else {
throw new IllegalArgumentException("Unsupported objectclass '" + objclass + "'");
}
}
/**
* {@inheritDoc}
*/
public void test() {
log.info("test connection");
connection.testConnection();
}
protected void buildUser(JSONObject result, ResultsHandler handler) {
try {
ConnectorObjectBuilder builder = new ConnectorObjectBuilder();
builder.setObjectClass(ObjectClass.ACCOUNT);
log.info("Building {1} results with Object: {0}", result.toString(), ObjectClass.ACCOUNT);
if (result.getString("Type").equalsIgnoreCase("Replicon.Domain.User")) {
} else {
log.error("Result is not a Replicon.Domain.User object");
}
log.info("Person contains {0} attributes", result.length());
JSONObject props = result.getJSONObject("Properties");
log.info("Person contains {0} properties", props.length());
builder.setUid(result.getString("Identity"));
builder.setName(props.getString("LoginName"));
Iterator itr = props.keys();
while (itr.hasNext()) {
String key = (String) itr.next();
String value = null;
try {
value = props.getString(key);
//log.info("Found Prop: {0} value: {1}", key, value);
} catch (JSONException ex) {}
if ((value != null) && (!(value.equalsIgnoreCase("null")))) {
// this is not great but it seems that JSON object strings break OpenIDM's parsing
if (!(value.contains("{"))){
log.info("Building Attr: {0} value: {1}", key, value);
builder.addAttribute(AttributeBuilder.build(key, value));
}
}
}
ConnectorObject co = builder.build();
log.info("Handling Connector Object Name: {0} Uid: {1} Class: {2}", co.getName(),co.getUid(),co.getObjectClass().getDisplayNameKey());
//Build and call handler for the person
handler.handle(co);
}
catch (JSONException ex) {
log.error("Error parsing JSON reult");
}
}
}