View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.openr66.protocol.localhandler;
21  
22  import org.waarp.common.logging.SysErrLogger;
23  import org.waarp.common.logging.WaarpLogger;
24  import org.waarp.common.logging.WaarpLoggerFactory;
25  import org.waarp.common.utility.WaarpShutdownHook;
26  import org.waarp.openr66.context.ErrorCode;
27  import org.waarp.openr66.context.R66FiniteDualStates;
28  import org.waarp.openr66.context.R66Result;
29  import org.waarp.openr66.context.R66Session;
30  import org.waarp.openr66.context.task.exception.OpenR66RunnerErrorException;
31  import org.waarp.openr66.database.data.DbTaskRunner;
32  import org.waarp.openr66.protocol.configuration.Configuration;
33  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoConnectionException;
34  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNotAuthenticatedException;
35  import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
36  import org.waarp.openr66.protocol.exception.OpenR66ProtocolRemoteShutdownException;
37  import org.waarp.openr66.protocol.exception.OpenR66ProtocolShutdownException;
38  import org.waarp.openr66.protocol.exception.OpenR66ProtocolSystemException;
39  import org.waarp.openr66.protocol.localhandler.packet.LocalPacketFactory;
40  import org.waarp.openr66.protocol.localhandler.packet.StartupPacket;
41  import org.waarp.openr66.protocol.localhandler.packet.ValidPacket;
42  import org.waarp.openr66.protocol.networkhandler.NetworkChannelReference;
43  import org.waarp.openr66.protocol.networkhandler.packet.NetworkPacket;
44  import org.waarp.openr66.protocol.utils.R66Future;
45  
46  import java.util.Collection;
47  import java.util.Iterator;
48  import java.util.concurrent.ConcurrentHashMap;
49  
50  /**
51   * This class handles Local Transaction connections
52   */
53  public class LocalTransaction {
54    /**
55     * Internal Logger
56     */
57    private static final WaarpLogger logger =
58        WaarpLoggerFactory.getLogger(LocalTransaction.class);
59  
60    /**
61     * HashMap of LocalChannelReference using LocalChannelId
62     */
63    private final ConcurrentHashMap<Integer, LocalChannelReference>
64        localChannelHashMap =
65        new ConcurrentHashMap<Integer, LocalChannelReference>();
66  
67    /**
68     * HashMap of LocalChannelReference using requested_requester_specialId
69     */
70    private final ConcurrentHashMap<String, LocalChannelReference>
71        localChannelHashMapIdBased =
72        new ConcurrentHashMap<String, LocalChannelReference>();
73  
74    /**
75     * Constructor
76     */
77    public LocalTransaction() {
78      // EMpty
79    }
80  
81    public final String hashStatus() {
82      return "LocalTransaction: [localChannelHashMap: " +
83             localChannelHashMap.size() + " localChannelHashMapIdBased: " +
84             localChannelHashMapIdBased.size() + "] ";
85    }
86  
87    /**
88     * Get the corresponding LocalChannelReference and set the remoteId if
89     * different
90     *
91     * @param remoteId
92     * @param localId
93     *
94     * @return the LocalChannelReference
95     *
96     * @throws OpenR66ProtocolSystemException
97     */
98    public final LocalChannelReference getClient(final Integer remoteId,
99                                                 final Integer localId)
100       throws OpenR66ProtocolSystemException {
101     final LocalChannelReference localChannelReference = getFromId(localId);
102     if (localChannelReference != null) {
103       if (localChannelReference.getRemoteId().compareTo(remoteId) != 0) {
104         localChannelReference.setRemoteId(remoteId);
105       }
106       return localChannelReference;
107     }
108     throw new OpenR66ProtocolSystemException(
109         "Cannot find LocalChannelReference");
110   }
111 
112   /**
113    * Create a new Client
114    *
115    * @param networkChannelReference
116    * @param remoteId might be set to ChannelUtils.NOCHANNEL (real
117    *     creation)
118    * @param futureRequest might be null (from NetworkChannel Startup)
119    *
120    * @return the LocalChannelReference
121    *
122    * @throws OpenR66ProtocolRemoteShutdownException
123    * @throws OpenR66ProtocolNoConnectionException
124    */
125   public final LocalChannelReference createNewClient(
126       final NetworkChannelReference networkChannelReference,
127       final Integer remoteId, final R66Future futureRequest,
128       final boolean fromSsl) throws OpenR66ProtocolRemoteShutdownException,
129                                     OpenR66ProtocolNoConnectionException {
130     if (WaarpShutdownHook.isShutdownStarting()) {
131       // Do not try since already locally in shutdown
132       throw new OpenR66ProtocolNoConnectionException(
133           "Cannot create client since the server is in shutdown.");
134     }
135     final LocalChannelReference localChannelReference =
136         new LocalChannelReference(networkChannelReference, remoteId,
137                                   futureRequest);
138     localChannelHashMap.put(localChannelReference.getLocalId(),
139                             localChannelReference);
140     logger.debug("Db connection done and Create LocalChannel entry: {}",
141                  localChannelReference);
142     // Now simulate sending first a Startup message
143     final StartupPacket startup =
144         new StartupPacket(localChannelReference.getLocalId(), fromSsl);
145     try {
146       localChannelReference.getServerHandler().startup(startup);
147       // Try but may not be available yet
148       localChannelReference.getServerHandler().validateAuthenticationReuse();
149     } catch (final OpenR66ProtocolPacketException e) {
150       throw new OpenR66ProtocolNoConnectionException(e);
151     } catch (final OpenR66ProtocolNotAuthenticatedException e) {
152       throw new OpenR66ProtocolNoConnectionException(e);
153     }
154     return localChannelReference;
155   }
156 
157   /**
158    * @param id
159    *
160    * @return the LocalChannelReference
161    */
162   public final LocalChannelReference getFromId(final Integer id) {
163     return localChannelHashMap.get(id);
164   }
165 
166   /**
167    * Remove one local channel
168    *
169    * @param localChannelReference
170    */
171   protected final void remove(
172       final LocalChannelReference localChannelReference) {
173     logger.debug("DEBUG remove: {}", localChannelReference.getLocalId());
174     localChannelHashMap.remove(localChannelReference.getLocalId());
175     if (localChannelReference.getRequestId() != null) {
176       localChannelHashMapIdBased.remove(localChannelReference.getRequestId());
177     }
178     if (localChannelReference.getNetworkChannelObject() != null) {
179       localChannelReference.getNetworkChannelObject()
180                            .remove(localChannelReference);
181     }
182   }
183 
184   /**
185    * @param runner
186    * @param lcr
187    */
188   public final void setFromId(final DbTaskRunner runner,
189                               final LocalChannelReference lcr) {
190     final String key = runner.getKey();
191     lcr.setRequestId(key);
192     localChannelHashMapIdBased.put(key, lcr);
193   }
194 
195   /**
196    * @param key as "requested requester specialId"
197    *
198    * @return the LocalChannelReference
199    */
200   public final LocalChannelReference getFromRequest(final String key) {
201     return localChannelHashMapIdBased.get(key);
202   }
203 
204   /**
205    * @param key as "requested requester specialId"
206    *
207    * @return True if the LocalChannelReference exists
208    */
209   public final boolean contained(final String key) {
210     return localChannelHashMapIdBased.containsKey(key);
211   }
212 
213   /**
214    * @param id
215    *
216    * @return True if the LocalChannelReference exists
217    */
218   public final boolean contained(final int id) {
219     return localChannelHashMap.containsKey(id);
220   }
221 
222   /**
223    * @return the number of active local channels
224    */
225   public final int getNumberLocalChannel() {
226     return localChannelHashMap.size();
227   }
228 
229   /**
230    * Debug function (while shutdown for instance)
231    */
232   public final void debugPrintActiveLocalChannels() {
233     final Collection<LocalChannelReference> collection =
234         localChannelHashMap.values();
235     for (final LocalChannelReference localChannelReference : collection) {
236       logger.debug("Will close local channel: {}", localChannelReference);
237       logger.debug(" Containing: {}",
238                    localChannelReference.getSession() != null?
239                        localChannelReference.getSession() : "no session");
240     }
241   }
242 
243   /**
244    * Informs all remote client that the server is shutting down
245    */
246   public final void shutdownLocalChannels() {
247     logger.warn(
248         "Will inform LocalChannels of Shutdown: " + localChannelHashMap.size());
249     final Collection<LocalChannelReference> collection =
250         localChannelHashMap.values();
251     final Iterator<LocalChannelReference> iterator = collection.iterator();
252     final ValidPacket packet = new ValidPacket("Shutdown forced", null,
253                                                LocalPacketFactory.SHUTDOWNPACKET);
254     while (iterator.hasNext()) {
255       final LocalChannelReference localChannelReference = iterator.next();
256       logger.info("Inform Shutdown {}", localChannelReference);
257       packet.setSmiddle(null);
258       packet.retain();
259       // If a transfer is running, save the current rank and inform remote
260       // host
261       if (localChannelReference.getSession() != null) {
262         final R66Session session = localChannelReference.getSession();
263         final DbTaskRunner runner = session.getRunner();
264         if (runner != null && runner.isInTransfer()) {
265           if (!session.isSender()) {
266             final int newrank = runner.getRank();
267             packet.setSmiddle(Integer.toString(newrank));
268           }
269           // Save File status
270           try {
271             runner.saveStatus();
272           } catch (final OpenR66RunnerErrorException ignored) {
273             // nothing
274           }
275         }
276         if (runner != null && !runner.isFinished()) {
277           final R66Result result =
278               new R66Result(new OpenR66ProtocolShutdownException(), session,
279                             true, ErrorCode.Shutdown, runner);
280           result.setOther(packet);
281           try {
282             final NetworkPacket message =
283                 new NetworkPacket(localChannelReference.getLocalId(),
284                                   localChannelReference.getRemoteId(), packet,
285                                   localChannelReference);
286             localChannelReference.sessionNewState(R66FiniteDualStates.SHUTDOWN);
287             try {
288               localChannelReference.getNetworkChannel().writeAndFlush(message)
289                                    .await(Configuration.WAITFORNETOP);
290             } catch (final InterruptedException e1) {//NOSONAR
291               SysErrLogger.FAKE_LOGGER.ignoreLog(e1);
292             }
293           } catch (final OpenR66ProtocolPacketException ignored) {
294             // ignore
295           }
296           try {
297             session.setFinalizeTransfer(false, result);
298           } catch (final OpenR66RunnerErrorException ignored) {
299             // ignore
300           } catch (final OpenR66ProtocolSystemException ignored) {
301             // ignore
302           }
303         }
304         localChannelReference.close();
305         continue;
306       }
307       try {
308         final NetworkPacket message =
309             new NetworkPacket(localChannelReference.getLocalId(),
310                               localChannelReference.getRemoteId(), packet,
311                               localChannelReference);
312         localChannelReference.getNetworkChannel().writeAndFlush(message);
313       } catch (final OpenR66ProtocolPacketException ignored) {
314         // ignore
315       }
316       localChannelReference.close();
317     }
318   }
319 
320   /**
321    * Close All Local Channels
322    */
323   public final void closeAll() {
324     logger.debug("close All Local Channels");
325     final Collection<LocalChannelReference> collection =
326         localChannelHashMap.values();
327     for (final LocalChannelReference localChannelReference : collection) {
328       logger.info("Inform Shutdown {}", localChannelReference);
329       localChannelReference.close();
330     }
331   }
332 
333 }