/**
* Copyright (c) 2008-2010 Mark Logic Corporation. All rights reserved.
*
* 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.
*
* The use of the Apache License does not indicate that this project is
* affiliated with the Apache Software Foundation.
*/
package com.marklogic.recordloader.xcc;
import java.math.BigInteger;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import com.marklogic.recordloader.Configuration;
import com.marklogic.recordloader.FatalException;
import com.marklogic.recordloader.FileLoader;
import com.marklogic.xcc.ContentCapability;
import com.marklogic.xcc.ContentPermission;
import com.marklogic.xcc.ContentSource;
import com.marklogic.xcc.ContentSourceFactory;
import com.marklogic.xcc.ContentbaseMetaData;
import com.marklogic.xcc.DocumentFormat;
import com.marklogic.xcc.DocumentRepairLevel;
import com.marklogic.xcc.SecurityOptions;
import com.marklogic.xcc.Session;
import com.marklogic.xcc.exceptions.XccConfigException;
import com.marklogic.xcc.exceptions.XccException;
/**
* @author Michael Blakeley, michael.blakeley@marklogic.com
*
*/
public class XccConfiguration extends Configuration {
public static final String CONNECTION_STRING_DEFAULT = "xcc://admin:admin@localhost:9000/";
public static final String CONTENT_MODULE_KEY = "CONTENT_MODULE_URI";
public static final String DOCUMENT_FORMAT_DEFAULT = DocumentFormat.XML
.toString();
public static final String QUALITY_KEY = "OUTPUT_QUALITY";
public static final String QUALITY_DEFAULT = "0";
Object metadataMutex = new Object();
volatile BigInteger[] placeKeys;
volatile ContentbaseMetaData metadata;
protected SecurityOptions securityOptions = null;
Object securityOptionsMutex = new Object();
protected DocumentRepairLevel repairLevel = DocumentRepairLevel.NONE;
protected DocumentFormat format = DocumentFormat.XML;
/**
* @return
* @throws XccException
*/
public BigInteger[] getPlaceKeys() {
return placeKeys;
}
/**
* @return
* @return
* @throws XccConfigException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public void initMetaData() throws XccConfigException,
KeyManagementException, NoSuchAlgorithmException {
if (null != metadata) {
return;
}
synchronized (metadataMutex) {
// check again, to prevent races
if (null != metadata) {
return;
}
URI uri = getConnectionStrings()[0];
// support SSL or plain-text
ContentSource cs = isSecure(uri) ? ContentSourceFactory
.newContentSource(uri, getSecurityOptions())
: ContentSourceFactory.newContentSource(uri);
// be sure to use the default db
Session session = cs.newSession();
metadata = session.getContentbaseMetaData();
// NB - this session is closed in the close() method
}
}
@Override
public void configure() {
super.configure();
// XCC-specific options
logger.info("configuring XCC-specific options");
String repairString = properties.getProperty(REPAIR_LEVEL_KEY);
if (repairString.equalsIgnoreCase("FULL")) {
repairLevel = DocumentRepairLevel.FULL;
}
String formatString = properties.getProperty(DOCUMENT_FORMAT_KEY)
.toLowerCase();
if (DocumentFormat.TEXT.toString().startsWith(formatString)) {
format = DocumentFormat.TEXT;
} else if (DocumentFormat.BINARY.toString().startsWith(
formatString)) {
format = DocumentFormat.BINARY;
} else if (DocumentFormat.XML.toString().startsWith(formatString)) {
format = DocumentFormat.XML;
} else {
logger.warning("Unexpected: " + DOCUMENT_FORMAT_KEY + "="
+ formatString + " (using xml)");
format = DocumentFormat.XML;
}
String[] placeNames = getOutputForests();
if (null != placeNames) {
try {
initMetaData();
Map<?, ?> forestMap = metadata.getForestMap();
placeKeys = new BigInteger[placeNames.length];
for (int i = 0; i < placeNames.length; i++) {
logger.finest("looking up " + placeNames[i]);
placeKeys[i] = (BigInteger) forestMap
.get(placeNames[i]);
if (null == placeKeys[i]) {
throw new FatalException("no forest named "
+ placeNames[i]);
}
logger.fine("mapping " + placeNames[i] + " to "
+ placeKeys[i]);
}
} catch (XccException e) {
throw new FatalException(e);
} catch (KeyManagementException e) {
throw new FatalException(e);
} catch (NoSuchAlgorithmException e) {
throw new FatalException(e);
}
}
}
protected static SecurityOptions newTrustAnyoneOptions()
throws KeyManagementException, NoSuchAlgorithmException {
TrustManager[] trust = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
/**
* @throws CertificateException
*/
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs,
String authType) throws CertificateException {
// no exception means it's okay
}
/**
* @throws CertificateException
*/
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs,
String authType) throws CertificateException {
// no exception means it's okay
}
} };
SSLContext sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(null, trust, null);
return new SecurityOptions(sslContext);
}
/**
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public SecurityOptions getSecurityOptions()
throws KeyManagementException, NoSuchAlgorithmException {
if (null != securityOptions) {
return securityOptions;
}
synchronized (securityOptionsMutex) {
if (null != securityOptions) {
return securityOptions;
}
securityOptions = newTrustAnyoneOptions();
return securityOptions;
}
}
/**
* @param _uri
* @return
*/
public boolean isSecure(URI _uri) {
// TODO would be nice if XCC exposed this string
return _uri.getScheme().equals("xccs");
}
public DocumentRepairLevel getRepairLevel() {
return repairLevel;
}
/**
* @return
*
* TODO - used only by XccContent. For XccModuleContent, we must
* break module API again.
*/
public int getQuality() {
return Integer.parseInt(properties.getProperty(QUALITY_KEY));
}
/**
* @return
*/
public boolean isFullRepair() {
return DocumentRepairLevel.FULL == repairLevel;
}
/**
* @return
*/
public DocumentFormat getFormat() {
return format;
}
/**
* @return
*/
public ContentPermission[] getPermissions() {
List<ContentPermission> permissions = new LinkedList<ContentPermission>();
buildPermissions(permissions, ContentPermission.EXECUTE,
getExecuteRoles());
buildPermissions(permissions, ContentPermission.INSERT,
getInsertRoles());
buildPermissions(permissions, ContentPermission.READ,
getReadRoles());
buildPermissions(permissions, ContentPermission.UPDATE,
getUpdateRoles());
logger.fine("returning " + permissions.size());
if (0 == permissions.size()) {
return null;
}
return permissions.toArray(new ContentPermission[0]);
}
/**
* @param permissions
* @param capability
* @param roles
*/
private void buildPermissions(List<ContentPermission> permissions,
ContentCapability capability, String[] roles) {
logger.fine("processing "
+ (null == roles ? roles : roles.length));
if (roles == null || roles.length < 1) {
return;
}
String name;
for (int i = 0; i < roles.length; i++) {
name = roles[i];
if (null == name) {
continue;
}
name = name.trim();
if ("".equals(name)) {
continue;
}
logger.finer("adding " + capability + " for " + name);
permissions.add(new ContentPermission(capability, name));
}
}
/**
* @return
*/
public String getContentModuleUri() {
return properties.getProperty(CONTENT_MODULE_KEY);
}
/**
* @return
* @throws NoSuchAlgorithmException
* @throws XccConfigException
* @throws KeyManagementException
*/
public String getDriverVersionString() throws KeyManagementException,
XccConfigException, NoSuchAlgorithmException {
initMetaData();
return metadata.getDriverVersionString();
}
/**
* @return
* @throws XccException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public String getServerVersionString() throws XccException,
KeyManagementException, NoSuchAlgorithmException {
initMetaData();
return metadata.getServerVersionString();
}
/*
* (non-Javadoc)
*
* @see com.marklogic.recordloader.AbstractConfiguration#close()
*/
@Override
public void close() {
if (null != metadata) {
metadata.getSession().close();
}
}
}