001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2010 Sun Microsystems, Inc. 025 * Portions Copyright 2012-2014 ForgeRock AS 026 */ 027package org.opends.server.tools.dsreplication; 028 029import static org.opends.messages.AdminToolMessages.*; 030import static org.opends.messages.CoreMessages.*; 031 032import java.io.File; 033 034import org.forgerock.i18n.LocalizableMessage; 035import org.forgerock.i18n.slf4j.LocalizedLogger; 036 037import org.opends.quicksetup.util.ProgressMessageFormatter; 038import org.opends.server.replication.plugin.LDAPReplicationDomain; 039import org.opends.server.types.DN; 040import org.opends.server.types.DirectoryEnvironmentConfig; 041import org.opends.server.types.DirectoryException; 042import org.opends.server.types.OpenDsException; 043import org.forgerock.opendj.ldap.ResultCode; 044import org.opends.server.util.EmbeddedUtils; 045import org.opends.server.util.StaticUtils; 046import org.opends.server.util.TimeThread; 047import com.forgerock.opendj.cli.ConsoleApplication; 048import org.opends.server.util.cli.PointAdder; 049 050/** 051 * The class that is in charge of taking the different information provided 052 * by the user through the command-line and actually executing the local 053 * purge. 054 * 055 */ 056public class LocalPurgeHistorical 057{ 058 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 059 060 private final PurgeHistoricalUserData uData; 061 private final ConsoleApplication app; 062 private final ProgressMessageFormatter formatter; 063 private final String configFile; 064 private final String configClass; 065 066 /** 067 * The default constructor. 068 * @param uData the object containing the information provided by the user. 069 * @param app the console application that is used to write the progress 070 * and error messages. 071 * @param formatter the formatter to be used to generated the messages. 072 * @param configFile the file that contains the configuration. This is 073 * required to initialize properly the server. 074 * @param configClass the class to be used to read the configuration. This is 075 * required to initialize properly the server. 076 */ 077 public LocalPurgeHistorical(PurgeHistoricalUserData uData, 078 ConsoleApplication app, 079 ProgressMessageFormatter formatter, String configFile, 080 String configClass) 081 { 082 this.uData = uData; 083 this.app = app; 084 this.formatter = formatter; 085 this.configFile = configFile; 086 this.configClass = configClass; 087 } 088 089 /** 090 * Executes the purge historical operation locally. 091 * @return the result code. 092 */ 093 public ReplicationCliReturnCode execute() 094 { 095 boolean applyTimeout = uData.getMaximumDuration() > 0; 096 097 long startTime = TimeThread.getTime(); 098 long purgeMaxTime = getTimeoutInSeconds() * 1000L; 099 100 long endMaxTime = startTime + purgeMaxTime; 101 102 app.print(formatter.getFormattedProgress( 103 INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_ENVIRONMENT.get())); 104 105 PointAdder pointAdder = new PointAdder(app); 106 pointAdder.start(); 107 108 Class<?> cfgClass; 109 110 try 111 { 112 cfgClass = Class.forName(configClass); 113 } 114 catch (Exception e) 115 { 116 pointAdder.stop(); 117 LocalizableMessage message = 118 ERR_CANNOT_LOAD_CONFIG_HANDLER_CLASS.get( 119 configClass, StaticUtils.stackTraceToSingleLineString(e)); 120 app.println(message); 121 logger.error(LocalizableMessage.raw("Error loading configuration class "+configClass+ 122 ": "+e, e)); 123 return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_CLASS_LOAD; 124 } 125 126 try 127 { 128 // Create a configuration for the server. 129 DirectoryEnvironmentConfig environmentConfig = 130 new DirectoryEnvironmentConfig(); 131 environmentConfig.setConfigClass(cfgClass); 132 environmentConfig.setConfigFile(new File(configFile)); 133 environmentConfig.setDisableConnectionHandlers(true); 134 EmbeddedUtils.startServer(environmentConfig); 135 } 136 catch (OpenDsException ode) 137 { 138 pointAdder.stop(); 139 LocalizableMessage message = ode.getMessageObject(); 140 ERR_CANNOT_LOAD_CONFIG_HANDLER_CLASS.get( 141 configClass, StaticUtils.stackTraceToSingleLineString(ode)); 142 app.println(message); 143 logger.error(LocalizableMessage.raw("Error starting server with file "+configFile+ 144 ": "+ode, ode)); 145 return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_SERVER_START; 146 } 147 pointAdder.stop(); 148 app.print(formatter.getFormattedDone()); 149 app.println(); 150 app.println(); 151 app.print(formatter.getFormattedProgress( 152 INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_STARTING.get())); 153 app.println(); 154 155 if (applyTimeout && timeoutOccurred(endMaxTime)) 156 { 157 return handleTimeout(); 158 } 159 160 try 161 { 162 // launch the job 163 for (String baseDN : uData.getBaseDNs()) 164 { 165 DN dn = DN.valueOf(baseDN); 166 // We can assume that this is an LDAP replication domain 167 LDAPReplicationDomain domain = 168 LDAPReplicationDomain.retrievesReplicationDomain(dn); 169 170 domain.purgeConflictsHistorical(null, startTime + purgeMaxTime); 171 } 172 173 } 174 catch (DirectoryException de) 175 { 176 if (de.getResultCode() == ResultCode.ADMIN_LIMIT_EXCEEDED) 177 { 178 return handleTimeout(); 179 } 180 else 181 { 182 return handleGenericExecuting(de); 183 } 184 } 185 return ReplicationCliReturnCode.SUCCESSFUL; 186 } 187 188 private ReplicationCliReturnCode handleGenericExecuting(OpenDsException ode) 189 { 190 logger.error(LocalizableMessage.raw("Error executing purge historical: "+ode, ode)); 191 app.println(); 192 app.println(ERR_REPLICATION_PURGE_HISTORICAL_EXECUTING.get( 193 ode.getMessageObject())); 194 return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_EXECUTING; 195 } 196 197 private ReplicationCliReturnCode handleTimeout() 198 { 199 app.println(); 200 app.println(ERR_REPLICATION_PURGE_HISTORICAL_TIMEOUT.get( 201 getTimeoutInSeconds())); 202 return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_TIMEOUT; 203 } 204 205 /** 206 * Returns the time-out provided by the user in seconds. 207 * @return the time-out provided by the user in seconds. 208 */ 209 private int getTimeoutInSeconds() 210 { 211 return uData.getMaximumDuration(); 212 } 213 214 /** 215 * A method that tells whether the maximum time to execute the operation was 216 * elapsed or not. 217 * @param endMaxTime the latest time in milliseconds when the operation should 218 * be completed. 219 * @return {@code true} if the time-out occurred and {@code false} otherwise. 220 */ 221 private boolean timeoutOccurred(long endMaxTime) 222 { 223 return TimeThread.getTime() > endMaxTime; 224 } 225}