Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.directory.studio.ldapbrowser.core.jobs; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.SearchResult; import org.apache.commons.codec.digest.DigestUtils; import org.apache.directory.api.dsmlv2.DsmlDecorator; import org.apache.directory.api.dsmlv2.response.BatchResponseDsml; import org.apache.directory.api.dsmlv2.response.SearchResponseDsml; import org.apache.directory.api.dsmlv2.response.SearchResultDoneDsml; import org.apache.directory.api.dsmlv2.response.SearchResultEntryDsml; import org.apache.directory.api.dsmlv2.response.SearchResultReferenceDsml; import org.apache.directory.api.dsmlv2.request.AddRequestDsml; import org.apache.directory.api.dsmlv2.request.BatchRequestDsml; import org.apache.directory.api.ldap.codec.api.LdapApiService; import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory; import org.apache.directory.api.ldap.model.entry.Attribute; import org.apache.directory.api.ldap.model.entry.AttributeUtils; import org.apache.directory.api.ldap.model.entry.Entry; import org.apache.directory.api.ldap.model.entry.Value; import org.apache.directory.api.ldap.model.exception.LdapException; import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException; import org.apache.directory.api.ldap.model.message.LdapResult; import org.apache.directory.api.ldap.model.message.MessageTypeEnum; import org.apache.directory.api.ldap.model.message.Response; import org.apache.directory.api.ldap.model.message.ResultCodeEnum; import org.apache.directory.api.ldap.model.message.SearchResultDone; import org.apache.directory.api.ldap.model.message.SearchResultDoneImpl; import org.apache.directory.api.ldap.model.name.Dn; import org.apache.directory.api.ldap.model.url.LdapUrl; import org.apache.directory.studio.common.core.jobs.StudioProgressMonitor; import org.apache.directory.studio.connection.core.Connection; import org.apache.directory.studio.connection.core.io.StudioNamingEnumeration; import org.apache.directory.studio.connection.core.jobs.StudioConnectionRunnableWithProgress; import org.apache.directory.studio.ldapbrowser.core.BrowserCoreMessages; import org.apache.directory.studio.ldapbrowser.core.model.IBrowserConnection; import org.apache.directory.studio.ldapbrowser.core.model.SearchParameter; import org.apache.directory.studio.ldapbrowser.core.utils.JNDIUtils; /** * Runnable for Exporting a part of a LDAP Server into a DSML File. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public class ExportDsmlRunnable implements StudioConnectionRunnableWithProgress { private static final String OBJECTCLASS_OBJECTCLASS_OID = "objectClass"; //$NON-NLS-1$ private static final String OBJECTCLASS_OBJECTCLASS_NAME = "2.5.4.0"; //$NON-NLS-1$ private static final String REFERRAL_OBJECTCLASS_OID = "2.16.840.1.113730.3.2.6"; //$NON-NLS-1$ private static final String REFERRAL_OBJECTCLASS_NAME = "referral"; //$NON-NLS-1$ private static final String REF_ATTRIBUTETYPE_OID = "2.16.840.1.113730.3.1.34"; //$NON-NLS-1$ private static final String REF_ATTRIBUTETYPE_NAME = "ref"; //$NON-NLS-1$ /** The name of the DSML file to export to */ private String exportDsmlFilename; /** The connection to use */ private IBrowserConnection browserConnection; /** The Search Parameter of the export*/ private SearchParameter searchParameter; /** The type of the export */ private ExportDsmlJobType type = ExportDsmlJobType.RESPONSE; /** * The LDAP Codec - for now need by the DSML Parser * @TODO - this should be removed - no reason why the DSML parser needs it * @TODO - hate to make it static like this but methods are static */ private static LdapApiService codec = LdapApiServiceFactory.getSingleton(); /** * This enum contains the two possible export types. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public enum ExportDsmlJobType { RESPONSE, REQUEST } /** * Creates a new instance of ExportDsmlRunnable. * * @param exportDsmlFilename * the name of the DSML file to export to * @param connection * the connection to use * @param searchParameter * the Search Parameter of the export */ public ExportDsmlRunnable(String exportDsmlFilename, IBrowserConnection connection, SearchParameter searchParameter, ExportDsmlJobType type) { this.exportDsmlFilename = exportDsmlFilename; this.browserConnection = connection; this.searchParameter = searchParameter; this.type = type; // Adding the name and OID of the 'ref' attribute to the list of returning attributes // for handling externals correctly List<String> returningAttributes = new ArrayList<>(Arrays.asList(searchParameter.getReturningAttributes())); returningAttributes.add(REF_ATTRIBUTETYPE_NAME); returningAttributes.add(REF_ATTRIBUTETYPE_OID); searchParameter.setReturningAttributes(returningAttributes.toArray(new String[0])); } /** * {@inheritDoc} */ public Connection[] getConnections() { return new Connection[] { browserConnection.getConnection() }; } /** * {@inheritDoc} */ public String getName() { return BrowserCoreMessages.jobs__export_dsml_name; } /** * {@inheritDoc} */ public Object[] getLockedObjects() { List<String> l = new ArrayList<>(); l.add(browserConnection.getUrl() + "_" + DigestUtils.shaHex(exportDsmlFilename)); //$NON-NLS-1$ return l.toArray(); } /** * {@inheritDoc} */ public String getErrorMessage() { return BrowserCoreMessages.jobs__export_dsml_error; } /** * {@inheritDoc} */ public void run(StudioProgressMonitor monitor) { monitor.beginTask(BrowserCoreMessages.jobs__export_dsml_task, 4); monitor.reportProgress(" "); //$NON-NLS-1$ monitor.worked(1); try { // Creating a dummy monitor that will be used to check if something // went wrong when executing the request StudioProgressMonitor dummyMonitor = new StudioProgressMonitor(monitor); // Searching for the requested entries StudioNamingEnumeration ne = SearchRunnable.search(browserConnection, searchParameter, dummyMonitor); monitor.worked(1); // Getting the DSML string associated to the search // and the type of answer the user is expecting String dsmlExportString = null; switch (type) { case RESPONSE: dsmlExportString = processAsDsmlResponse(ne, dummyMonitor); break; case REQUEST: dsmlExportString = processAsDsmlRequest(ne, dummyMonitor); break; } monitor.worked(1); // Writing the DSML string to the final destination file. if (dsmlExportString != null) { try (FileOutputStream fos = new FileOutputStream(exportDsmlFilename)) { try (OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8")) //$NON-NLS-1$ { try (BufferedWriter bufferedWriter = new BufferedWriter(osw)) { bufferedWriter.write(dsmlExportString); } } } } monitor.worked(1); } catch (Exception e) { monitor.reportError(e); } } /** * Processes the {@link NamingEnumeration} as a DSML response. * * @param ne the naming enumeration * @param monitor the monitor * @return the associated DSML * @throws LdapException */ private String processAsDsmlResponse(StudioNamingEnumeration ne, StudioProgressMonitor monitor) throws LdapException { // Creating the batch reponse BatchResponseDsml batchResponse = new BatchResponseDsml(); processAsDsmlResponse(ne, batchResponse, monitor, searchParameter); // Returning the associated DSML return batchResponse.toDsml(); } /** * Processes the {@link NamingEnumeration} as a DSML response. * * @param ne * the naming enumeration * @param monitor * the monitor * @param searchParameter * the search parameter * @throws LdapURLEncodingException * @throws org.apache.directory.api.ldap.model.exception.LdapException */ public static void processAsDsmlResponse(StudioNamingEnumeration ne, BatchResponseDsml batchResponse, StudioProgressMonitor monitor, SearchParameter searchParameter) throws LdapException { // Creating and adding the search response SearchResponseDsml sr = new SearchResponseDsml(codec); batchResponse.addResponse(sr); try { int count = 0; if (!monitor.errorsReported()) { // Creating and adding a search result entry or reference for each result while (ne.hasMore()) { SearchResult searchResult = ne.next(); sr.addResponse(convertSearchResultToDsml(searchResult)); count++; monitor.reportProgress(BrowserCoreMessages.bind(BrowserCoreMessages.jobs__export_progress, new String[] { Integer.toString(count) })); } } } catch (NamingException e) { int ldapStatusCode = JNDIUtils.getLdapStatusCode(e); if (ldapStatusCode == 3 || ldapStatusCode == 4 || ldapStatusCode == 11) { // ignore } else { monitor.reportError(e); } } // Creating and adding a search result done at the end of the results SearchResultDone srd = new SearchResultDoneImpl(); LdapResult ldapResult = srd.getLdapResult(); if (!monitor.errorsReported()) { ldapResult.setResultCode(ResultCodeEnum.SUCCESS); } else { // Getting the exception Throwable t = monitor.getException(); // Setting the result code ldapResult.setResultCode(ResultCodeEnum.getBestEstimate(t, MessageTypeEnum.SEARCH_REQUEST)); // Setting the error message if there's one if (t.getMessage() != null) { ldapResult.setDiagnosticMessage(t.getMessage()); } } sr.addResponse(new SearchResultDoneDsml(codec, srd)); } /** * Converts the given {@link SearchResult} to a {@link SearchResultEntryDsml}. * * @param searchResult the search result * @return the associated search result entry DSML * @throws org.apache.directory.api.ldap.model.exception.LdapException */ private static DsmlDecorator<? extends Response> convertSearchResultToDsml(SearchResult searchResult) throws LdapException { Entry entry = AttributeUtils.toEntry(searchResult.getAttributes(), new Dn(searchResult.getNameInNamespace())); if (isReferral(entry)) { // The search result is a referral SearchResultReferenceDsml srr = new SearchResultReferenceDsml(codec); // Getting the 'ref' attribute Attribute refAttribute = entry.get(ExportDsmlRunnable.REF_ATTRIBUTETYPE_NAME); if (refAttribute == null) { // If we did not get it by its name, let's get it by its OID refAttribute = entry.get(ExportDsmlRunnable.REF_ATTRIBUTETYPE_OID); } // Adding references if (refAttribute != null) { for (Value value : refAttribute) { srr.addSearchResultReference(new LdapUrl((String) value.getValue())); } } return srr; } else { // The search result is NOT a referral SearchResultEntryDsml sre = new SearchResultEntryDsml(codec); sre.setEntry(entry); return sre; } } /** * Indicates if the given entry is a referral. * * @param entry * the entry * @return * <code>true</code> if the given entry is a referral, <code>false</code> if not */ private static boolean isReferral(Entry entry) { if (entry != null) { // Getting the 'objectClass' Attribute Attribute objectClassAttribute = entry.get(ExportDsmlRunnable.OBJECTCLASS_OBJECTCLASS_NAME); if (objectClassAttribute == null) { objectClassAttribute = entry.get(ExportDsmlRunnable.OBJECTCLASS_OBJECTCLASS_OID); } if (objectClassAttribute != null) { // Checking if the 'objectClass' attribute contains the // 'referral' object class as value return ((objectClassAttribute.contains(ExportDsmlRunnable.REFERRAL_OBJECTCLASS_NAME)) || (objectClassAttribute.contains(ExportDsmlRunnable.REFERRAL_OBJECTCLASS_OID))); } } return false; } /** * Processes the {@link NamingEnumeration} as a DSML request. * * @param ne * the naming enumeration * @param monitor * the monitor * @return * the associated DSML * @throws NamingException * @throws LdapException */ private String processAsDsmlRequest(StudioNamingEnumeration ne, StudioProgressMonitor monitor) throws NamingException, LdapException { // Creating the batch request BatchRequestDsml batchRequest = new BatchRequestDsml(); try { int count = 0; if (!monitor.errorsReported()) { // Creating and adding an add request for each result while (ne.hasMore()) { SearchResult searchResult = ne.next(); AddRequestDsml arDsml = convertToAddRequestDsml(searchResult); batchRequest.addRequest(arDsml); count++; monitor.reportProgress(BrowserCoreMessages.bind(BrowserCoreMessages.jobs__export_progress, new String[] { Integer.toString(count) })); } } } catch (NamingException e) { int ldapStatusCode = JNDIUtils.getLdapStatusCode(e); if (ldapStatusCode == 3 || ldapStatusCode == 4 || ldapStatusCode == 11) { // ignore } else { monitor.reportError(e); } } // Returning the associated DSML return batchRequest.toDsml(); } /** * Converts the given {@link SearchResult} to an {@link AddRequestDsml}. * * @param searchResult * the {@link SearchResult} * @return * the associated {@link AddRequestDsml} * @throws LdapException */ private AddRequestDsml convertToAddRequestDsml(SearchResult searchResult) throws LdapException { AddRequestDsml ar = new AddRequestDsml(codec); Entry entry = AttributeUtils.toEntry(searchResult.getAttributes(), new Dn(searchResult.getNameInNamespace())); ar.setEntry(entry); return ar; } }