1 | // Copyright 2004-2007 Jean-Francois Poilpret |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | package net.sourceforge.hivetranse.transaction.ibatis; |
16 | |
17 | import java.io.IOException; |
18 | import java.io.InputStreamReader; |
19 | import java.lang.reflect.InvocationHandler; |
20 | import java.lang.reflect.InvocationTargetException; |
21 | import java.lang.reflect.Method; |
22 | import java.lang.reflect.Proxy; |
23 | import java.sql.Connection; |
24 | |
25 | import org.apache.commons.logging.Log; |
26 | import org.apache.hivemind.ApplicationRuntimeException; |
27 | import org.apache.hivemind.Resource; |
28 | import org.apache.hivemind.ServiceImplementationFactory; |
29 | import org.apache.hivemind.ServiceImplementationFactoryParameters; |
30 | import org.apache.hivemind.util.ToStringBuilder; |
31 | |
32 | import com.ibatis.sqlmap.client.SqlMapClient; |
33 | import com.ibatis.sqlmap.client.SqlMapClientBuilder; |
34 | |
35 | /** |
36 | * This service creates Proxys to iBATIS SqlMapClient (V2). |
37 | * <p> |
38 | * <b>ServiceModel must be singleton</b> |
39 | * |
40 | * @author Jean-Francois Poilpret |
41 | */ |
42 | public class SqlMapClientFactory implements ServiceImplementationFactory |
43 | { |
44 | public Object createCoreServiceImplementation( |
45 | ServiceImplementationFactoryParameters factoryParams) |
46 | { |
47 | Log logger = factoryParams.getLog(); |
48 | String serviceId = factoryParams.getServiceId(); |
49 | Class serviceInterface = factoryParams.getServiceInterface(); |
50 | |
51 | // Make sure that serviceInterface == SqlMapClient |
52 | // (this factory is dedicated exclusively to iBATIS SqlMapClients) |
53 | if (!SqlMapClient.class.equals(serviceInterface)) |
54 | { |
55 | // throw error |
56 | logger.error("SqlMapClientFactory can only build SqlMapClient services."); |
57 | throw new ApplicationRuntimeException("Bad interface"); |
58 | } |
59 | |
60 | // Read parameter |
61 | SqlMapClientFactoryContribution contrib = |
62 | (SqlMapClientFactoryContribution) factoryParams.getFirstParameter(); |
63 | SqlMapClient client = buildSqlMapClient(logger, contrib.getConfig()); |
64 | |
65 | return Proxy.newProxyInstance( |
66 | factoryParams.getInvokingModule().getClassResolver().getClassLoader(), |
67 | new Class[] {serviceInterface}, |
68 | new SqlMapClientProxy(logger, serviceId, contrib.getConnection(), client)); |
69 | } |
70 | |
71 | protected SqlMapClient buildSqlMapClient(Log logger, Resource config) |
72 | { |
73 | java.net.URL url = config.getResourceURL(); |
74 | if (url == null) |
75 | { |
76 | logger.error("Cannot open " + config.getName()); |
77 | throw new ApplicationRuntimeException("Bad configuration file"); |
78 | } |
79 | InputStreamReader input; |
80 | try |
81 | { |
82 | input = new InputStreamReader(url.openStream()); |
83 | } |
84 | catch (IOException e) |
85 | { |
86 | logger.error("buildSqlMapClient", e); |
87 | throw new ApplicationRuntimeException("buildSqlMapClient", e); |
88 | } |
89 | |
90 | SqlMapClient client = SqlMapClientBuilder.buildSqlMapClient(input); |
91 | |
92 | return client; |
93 | } |
94 | |
95 | static private class SqlMapClientProxy implements InvocationHandler |
96 | { |
97 | public SqlMapClientProxy( Log logger, |
98 | String serviceId, |
99 | Connection connection, |
100 | SqlMapClient client) |
101 | { |
102 | _logger = logger; |
103 | _serviceId = serviceId; |
104 | _connection = connection; |
105 | _client = client; |
106 | } |
107 | |
108 | //CSOFF: IllegalThrowsCheck |
109 | public Object invoke(Object proxy, Method method, Object[] args) |
110 | throws Throwable |
111 | { |
112 | if ("toString".equals(method.getName())) |
113 | { |
114 | ToStringBuilder builder = new ToStringBuilder(this); |
115 | builder.append("serviceId", _serviceId); |
116 | return builder.toString(); |
117 | } |
118 | |
119 | // Set the user Connection (the reference is always the same, but |
120 | // the actual Connection can change in fact). We call this method to |
121 | // make sure the SqlMapClient is aware of it) |
122 | _client.setUserConnection(_connection); |
123 | |
124 | try |
125 | { |
126 | return method.invoke(_client, args); |
127 | } |
128 | catch (IllegalAccessException e) |
129 | { |
130 | // Can never happen (normally!) |
131 | _logger.fatal("Unexpected", e); |
132 | throw e; |
133 | } |
134 | catch (InvocationTargetException e) |
135 | { |
136 | throw e.getTargetException(); |
137 | } |
138 | } |
139 | //CSON: IllegalThrowsCheck |
140 | |
141 | private final Log _logger; |
142 | private final String _serviceId; |
143 | private final Connection _connection; |
144 | private final SqlMapClient _client; |
145 | } |
146 | } |