View Javadoc

1   /*
2    * #%L
3    * Bitrepository Access
4    * 
5    * $Id$
6    * $HeadURL$
7    * %%
8    * Copyright (C) 2010 - 2011 The State and University Library, The Royal Library and The State Archives, Denmark
9    * %%
10   * This program is free software: you can redistribute it and/or modify
11   * it under the terms of the GNU Lesser General Public License as 
12   * published by the Free Software Foundation, either version 2.1 of the 
13   * License, or (at your option) any later version.
14   * 
15   * This program is distributed in the hope that it will be useful,
16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   * GNU General Lesser Public License for more details.
19   * 
20   * You should have received a copy of the GNU General Lesser Public 
21   * License along with this program.  If not, see
22   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
23   * #L%
24   */
25  package org.bitrepository.modify.putfile.conversation;
26  
27  import org.bitrepository.bitrepositoryelements.ResponseCode;
28  import org.bitrepository.bitrepositorymessages.IdentifyPillarsForPutFileRequest;
29  import org.bitrepository.bitrepositorymessages.IdentifyPillarsForPutFileResponse;
30  import org.bitrepository.bitrepositorymessages.MessageResponse;
31  import org.bitrepository.client.conversation.ConversationContext;
32  import org.bitrepository.client.conversation.GeneralConversationState;
33  import org.bitrepository.client.conversation.IdentifyingState;
34  import org.bitrepository.common.exceptions.UnableToFinishException;
35  import org.bitrepository.common.utils.ChecksumUtils;
36  
37  /**
38   * Handles the identification phase of the PutFile operation.
39   */
40  public class IdentifyPillarsForPutFile extends IdentifyingState {
41      private final PutFileConversationContext context;
42  
43      /**
44       * @param context The shared conversation context.
45       */
46      public IdentifyPillarsForPutFile(PutFileConversationContext context) {
47          super(context.getContributors());
48          this.context = context;
49      }
50  
51      /**
52       * Extends the default behaviour with a idempotent aspects. This assumes that the put to a pillar is successful if
53       * the same file already exists.
54       *
55       * The existence of a different file on the other hand is a fatal problem.
56       */
57      @Override
58      protected void handleFailureResponse(MessageResponse msg) throws UnableToFinishException {
59          IdentifyPillarsForPutFileResponse response = (IdentifyPillarsForPutFileResponse) msg;
60          ResponseCode responseCode = response.getResponseInfo().getResponseCode();
61          switch (responseCode) {
62              case DUPLICATE_FILE_FAILURE:
63                  if(response.isSetChecksumDataForExistingFile()) {
64                      if(ChecksumUtils.areEqual(
65                              response.getChecksumDataForExistingFile(),context.getChecksumForValidationAtPillar())) {
66                          PutFileCompletePillarEvent event = new PutFileCompletePillarEvent(
67                                  response.getPillarID(), response.getCollectionID(), response.getChecksumDataForExistingFile());
68                          event.setInfo("File already existed on " + response.getPillarID());
69                          getContext().getMonitor().contributorComplete(event);
70                      } else {
71                          getContext().getMonitor().contributorFailed(
72                                  "Received negative response from component " + response.getFrom() +
73                                          ":  " + response.getResponseInfo() + " (existing file checksum does not match)",
74                                  response.getFrom(), response.getResponseInfo().getResponseCode());
75                          throw new UnableToFinishException("Can not put file " + context.getFileID() +
76                                  ", as an different file already exists on pillar " + response.getPillarID());
77                      }
78                  } else {
79                      getContext().getMonitor().contributorFailed(
80                              "Received negative response from component " + response.getFrom() + ":  " +
81                                      response.getResponseInfo(), response.getFrom(), 
82                                      response.getResponseInfo().getResponseCode());
83                      throw new UnableToFinishException("Can not put file " + context.getFileID() +
84                              ", as an file already exists on pillar " + response.getPillarID());
85                  }
86                  break;
87              default:
88                  super.handleFailureResponse(msg);
89          }
90      }
91  
92      @Override
93      public GeneralConversationState getOperationState() throws UnableToFinishException {
94          return new PuttingFile(context, getSelector().getSelectedComponents());
95      }
96  
97      @Override
98      protected void sendRequest() {
99          IdentifyPillarsForPutFileRequest msg = new IdentifyPillarsForPutFileRequest();
100         initializeMessage(msg);
101         msg.setFileID(context.getFileID());
102         msg.setFileSize(context.getFileSize());
103         msg.setDestination(context.getSettings().getCollectionDestination());
104         context.getMessageSender().sendMessage(msg);
105         context.getMonitor().identifyRequestSent("Identifying pillars for put file");
106     }
107 
108     @Override
109     protected ConversationContext getContext() {
110         return context;
111     }
112 
113     @Override
114     protected String getPrimitiveName() {
115         return "IdentifyPillarsForPutFile";
116     }
117 
118     /**
119      * Extends the default behaviour with the possiblity of putting to a subset of pillars, if the
120      * isSetPartialPutsAllow settings is true.
121      * */
122     @Override
123     protected boolean canFinish() {
124         return (isPartialPutsAllowed() && getSelector().getSelectedComponents().size() > 0 ||
125                 getOutstandingComponents().isEmpty());
126     }
127 
128     private boolean isPartialPutsAllowed() {
129         boolean isPartialPutsAllowed = true;
130         if (context.getSettings().getReferenceSettings().getPutFileSettings() != null &&
131                 context.getSettings().getReferenceSettings().getPutFileSettings().isSetPartialPutsAllow()) {
132             isPartialPutsAllowed = context.getSettings().getReferenceSettings().getPutFileSettings().isPartialPutsAllow();
133         }
134         return isPartialPutsAllowed;
135     }
136 
137     @Override
138     protected void checkForChecksumPillar(MessageResponse msg) {
139         IdentifyPillarsForPutFileResponse response = (IdentifyPillarsForPutFileResponse) msg;
140         if (response.getPillarChecksumSpec() != null) {
141             context.addChecksumPillar(response.getPillarID());
142         }
143     }
144 }