View Javadoc

1   /**
2      This file is part of GoldenGate Project (named also GoldenGate or GG).
3   
4      Copyright 2009, Frederic Bregier, 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 GoldenGate Project is free software: you can redistribute it and/or 
9      modify it under the terms of the GNU General Public License as published 
10     by the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12  
13     GoldenGate is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17  
18     You should have received a copy of the GNU General Public License
19     along with GoldenGate .  If not, see <http://www.gnu.org/licenses/>.
20   */
21  package goldengate.commandexec.client;
22  
23  import goldengate.commandexec.utils.LocalExecDefaultResult;
24  import goldengate.commandexec.utils.LocalExecResult;
25  import goldengate.common.future.GgFuture;
26  import goldengate.common.logging.GgInternalLogger;
27  import goldengate.common.logging.GgInternalLoggerFactory;
28  
29  import org.jboss.netty.channel.ChannelHandlerContext;
30  import org.jboss.netty.channel.ChannelStateEvent;
31  import org.jboss.netty.channel.ExceptionEvent;
32  import org.jboss.netty.channel.MessageEvent;
33  import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
34  
35  /**
36   * Handles a client-side channel for LocalExec
37   *
38   *
39   */
40  public class LocalExecClientHandler extends SimpleChannelUpstreamHandler {
41  
42      /**
43       * Internal Logger
44       */
45      private static final GgInternalLogger logger = GgInternalLoggerFactory
46              .getLogger(LocalExecClientHandler.class);
47  
48  
49      private LocalExecResult result;
50      private StringBuilder back;
51      private boolean firstMessage = true;
52      private GgFuture future;
53      protected LocalExecClientPipelineFactory factory = null;
54      /**
55       * Constructor
56       */
57      public LocalExecClientHandler(LocalExecClientPipelineFactory factory) {
58          this.factory = factory;
59      }
60  
61      /**
62       * Initialize the client status for a new execution
63       */
64      public void initExecClient() {
65          this.result = new LocalExecResult(LocalExecDefaultResult.NoStatus);
66          this.back = new StringBuilder();
67          this.firstMessage = true;
68          this.future = new GgFuture(true);
69      }
70  
71      /* (non-Javadoc)
72       * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent)
73       */
74      @Override
75      public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
76              throws Exception {
77          initExecClient();
78          factory.addChannel(ctx.getChannel());
79      }
80  
81      /* (non-Javadoc)
82       * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#channelDisconnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent)
83       */
84      @Override
85      public void channelDisconnected(ChannelHandlerContext ctx,
86              ChannelStateEvent e) throws Exception {
87          this.factory.removeChannel(e.getChannel());
88      }
89  
90      /**
91       * When closed, <br>
92       * If no messaged were received => NoMessage error is set to future<br>
93       * Else if an error was detected => Set the future to error (with or without exception)<br>
94       * Else if no error occurs => Set success to the future<br>
95       *
96       *
97       * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#channelClosed(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent)
98       */
99      @Override
100     public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
101             throws Exception {
102         logger.debug("ChannelClosed");
103         if (!future.isDone()) {
104             // Should not be
105             finalizeMessage();
106         }
107         super.channelClosed(ctx, e);
108     }
109     /**
110      * Finalize a message
111      */
112     private void finalizeMessage() {
113         if (firstMessage) {
114             logger.warn(result.status+" "+result.result);
115             result.set(LocalExecDefaultResult.NoMessage);
116         } else {
117             result.result = back.toString();
118         }
119         if (result.status < 0) {
120             if (result.exception != null) {
121                 this.future.setFailure(result.exception);
122             } else {
123                 this.future.cancel();
124             }
125         } else {
126             this.future.setSuccess();
127         }
128     }
129     /**
130      * Waiting for the close of the exec
131      * @return The LocalExecResult
132      */
133     public LocalExecResult waitFor(long delay) {
134         if (delay <= 0) {
135             this.future.awaitUninterruptibly();
136         } else {
137             this.future.awaitUninterruptibly(delay);
138         }
139         result.isSuccess = this.future.isSuccess();
140         return result;
141     }
142 
143     @Override
144     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
145         // Add the line received from the server.
146         String mesg = (String) e.getMessage();
147         // If first message, then take the status and then the message
148         if (firstMessage) {
149             firstMessage = false;
150             int pos = mesg.indexOf(' ');
151             try {
152                 result.status = Integer.parseInt(mesg.substring(0, pos));
153             } catch (NumberFormatException e1) {
154                 // Error
155                 result.set(LocalExecDefaultResult.BadTransmition);
156                 back.append(mesg);
157                 ctx.getChannel().close();
158                 return;
159             }
160             mesg = mesg.substring(pos+1);
161             result.result = mesg;
162             back.append(mesg);
163         } else if (LocalExecDefaultResult.ENDOFCOMMAND.startsWith(mesg)) {
164             logger.debug("Receive End of Command");
165             this.finalizeMessage();
166         } else {
167             back.append('\n');
168             back.append(mesg);
169         }
170     }
171 
172     @Override
173     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
174         logger.error("Unexpected exception from downstream while get information: "+firstMessage,
175                 e.getCause());
176         if (firstMessage) {
177             firstMessage = false;
178             result.set(LocalExecDefaultResult.BadTransmition);
179             result.exception = (Exception) e.getCause();
180             back = new StringBuilder("Error in LocalExec: ");
181             back.append(result.exception.getMessage());
182             back.append('\n');
183         } else {
184             back.append("\nERROR while receiving answer: ");
185             result.exception = (Exception) e.getCause();
186             back.append(result.exception.getMessage());
187             back.append('\n');
188         }
189         e.getChannel().close();
190     }
191 }