1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 
20 
21 public struct TApplicationError : TError {
22   public enum Code : TErrorCode {
23     case unknown
24     case unknownMethod(methodName: String?)
25     case invalidMessageType
26     case wrongMethodName(methodName: String?)
27     case badSequenceId
28     case missingResult(methodName: String?)
29     case internalError
30     case protocolError
31     case invalidTransform
32     case invalidProtocol
33     case unsupportedClientType
34 
35 
36     /// Initialize a TApplicationError with a Thrift error code
37     /// Normally this would be achieved with RawRepresentable however
38     /// by doing this we can allow for associated properties on enum cases for
39     /// case specific context data in a Swifty, type-safe manner.
40     ///
41     /// - parameter thriftErrorCode: Integer TApplicationError(exception) error code.
42     ///                              Default to 0 (.unknown)
43     public init(thriftErrorCode: Int) {
44       switch thriftErrorCode {
45       case 1:  self = .unknownMethod(methodName: nil)
46       case 2:  self = .invalidMessageType
47       case 3:  self = .wrongMethodName(methodName: nil)
48       case 4:  self = .badSequenceId
49       case 5:  self = .missingResult(methodName: nil)
50       case 6:  self = .internalError
51       case 7:  self = .protocolError
52       case 8:  self = .invalidProtocol
53       case 9:  self = .invalidTransform
54       case 10: self = .unsupportedClientType
55       default: self = .unknown
56       }
57     }
58     public var thriftErrorCode: Int {
59       switch self {
60       case .unknown:                return 0
61       case .unknownMethod:          return 1
62       case .invalidMessageType:     return 2
63       case .wrongMethodName:        return 3
64       case .badSequenceId:          return 4
65       case .missingResult:          return 5
66       case .internalError:          return 6
67       case .protocolError:          return 7
68       case .invalidProtocol:        return 8
69       case .invalidTransform:       return 9
70       case .unsupportedClientType:  return 10
71       }
72     }
73 
74     public var description: String {
75       /// Output "for #methodName" if method is not nil else empty
76       let methodUnwrap: (String?) -> String =  { method in
77         return "\(method == nil ? "" : " for \(method ?? "")")"
78       }
79       switch self {
80       case .unknown:                      return "Unknown TApplicationError"
81       case .unknownMethod(let method):    return "Unknown Method\(methodUnwrap(method))"
82       case .invalidMessageType:           return "Invalid Message Type"
83       case .wrongMethodName(let method):  return "Wrong Method Name\(methodUnwrap(method))"
84       case .badSequenceId:                return "Bad Sequence ID"
85       case .missingResult(let method):    return "Missing Result\(methodUnwrap(method))"
86       case .internalError:                return "Internal Error"
87       case .protocolError:                return "Protocol Error"
88       case .invalidProtocol:              return "Invalid Protocol"
89       case .invalidTransform:             return "Invalid Transform"
90       case .unsupportedClientType:        return "Unsupported Client Type"
91       }
92     }
93   }
94 
95   public init() { }
96 
97   public init(thriftErrorCode code: Int, message: String? = nil) {
98     self.error = Code(thriftErrorCode: code)
99     self.message = message
100   }
101 
102   public var error: Code = .unknown
103   public var message: String? = nil
104   public static var defaultCase: Code { return .unknown }
105 }
106 
107 extension TApplicationError : TSerializable {
108   public static var thriftType: TType { return .struct }
109 
readnull110   public static func read(from proto: TProtocol) throws -> TApplicationError {
111     var errorCode: Int = 0
112     var message: String? = nil
113     _ = try proto.readStructBegin()
114     fields: while true {
115       let (_, fieldType, fieldID) = try proto.readFieldBegin()
116 
117       switch (fieldID, fieldType) {
118       case (_, .stop):
119         break fields
120       case (1, .string):
121         message = try proto.read()
122       case (2, .i32):
123         errorCode = Int(try proto.read() as Int32)
124 
125       case let (_, unknownType):
126         try proto.skip(type: unknownType)
127       }
128 
129       try proto.readFieldEnd()
130     }
131     try proto.readStructEnd()
132     return TApplicationError(thriftErrorCode: errorCode, message: message)
133   }
134 
writenull135   public func write(to proto: TProtocol) throws {
136     try proto.writeStructBegin(name: "TApplicationException")
137 
138     try proto.writeFieldBegin(name: "message", type: .string, fieldID: 1)
139     try proto.write(message ?? "")
140     try proto.writeFieldEnd()
141 
142     try proto.writeFieldBegin(name: "type", type: .i32, fieldID: 2)
143     let val = Int32(error.thriftErrorCode)
144     try proto.write(val)
145     try proto.writeFieldEnd()
146     try proto.writeFieldStop()
147     try proto.writeStructEnd()
148   }
149 
150   public var hashValue: Int {
151     return error.thriftErrorCode &+ (message?.hashValue ?? 0)
152   }
153 }
154 
==null155 public func ==(lhs: TApplicationError, rhs: TApplicationError) -> Bool {
156   return lhs.error.thriftErrorCode == rhs.error.thriftErrorCode && lhs.message == rhs.message
157 }
158