├── README.md ├── .gitignore ├── src ├── main │ └── java │ │ └── com │ │ └── weibo │ │ └── yar │ │ ├── packager │ │ ├── Packager.java │ │ ├── JsonPackager.java │ │ ├── PackagerFactory.java │ │ ├── PherializePackager.java │ │ └── MsgpackPackager.java │ │ ├── yarclient │ │ ├── YarClient.java │ │ ├── HttpYarClient.java │ │ └── AbstractYarClient.java │ │ ├── YarException.java │ │ ├── yarserver │ │ ├── HttpServerHandler.java │ │ └── NettyYarServer.java │ │ ├── YarRequest.java │ │ ├── YarHeader.java │ │ ├── YarResponse.java │ │ ├── YarProtocol.java │ │ └── codec │ │ └── PHPUnserializer.java └── test │ └── java │ └── com │ └── weibo │ └── yar │ ├── packager │ ├── MsgpackPackagerTest.java │ ├── PherializePackagerTest.java │ └── BasePackagerTest.java │ └── YarProtocolTest.java ├── pom.xml └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # yar-java 2 | Java implementation of Yar protocol 3 | 4 | ## Usage 5 | 6 | ### maven 7 | 8 | ```xml 9 | ... 10 | 11 | 12 | com.weibo 13 | yar-java 14 | 0.0.3 15 | 16 | 17 | ... 18 | ``` 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .target/ 2 | .logs/ 3 | */logs/ 4 | */*/logs/ 5 | */target/ 6 | 7 | # maven ignore 8 | target/ 9 | *.war 10 | *.zip 11 | *.tar 12 | *.tar.gz 13 | 14 | # eclipse ignore 15 | .settings/ 16 | .project 17 | .classpath 18 | 19 | # idea ignore 20 | .idea/ 21 | *.ipr 22 | *.iml 23 | *.iws 24 | 25 | # temp ignore 26 | *.log 27 | *.cache 28 | *.diff 29 | *.patch 30 | *.tmp 31 | 32 | # system ignore 33 | .DS_Store 34 | Thumbs.db 35 | logs/ 36 | bin/ 37 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/packager/Packager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.packager; 15 | 16 | import java.io.IOException; 17 | 18 | 19 | public interface Packager { 20 | 21 | byte[] encode(E value) throws IOException; 22 | 23 | E decode(byte[] data, Class messageType) throws IOException; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/yar/packager/MsgpackPackagerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.weibo.yar.packager; 17 | 18 | 19 | public class MsgpackPackagerTest extends BasePackagerTest { 20 | 21 | protected void setUp() throws Exception { 22 | packager = new MsgpackPackager(); 23 | } 24 | 25 | protected void tearDown() throws Exception { 26 | super.tearDown(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/yar/packager/PherializePackagerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.weibo.yar.packager; 17 | 18 | 19 | public class PherializePackagerTest extends BasePackagerTest { 20 | 21 | protected void setUp() throws Exception { 22 | packager = new PherializePackager(); 23 | } 24 | 25 | protected void tearDown() throws Exception { 26 | super.tearDown(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/yarclient/YarClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.yarclient; 15 | 16 | import java.io.IOException; 17 | 18 | public interface YarClient { 19 | public E call(String path, String method, Class responseClass, Object... parameterObject) throws IOException; 20 | 21 | public E call(String path, String method, String packageName, Class responseClass, Object... parameterObject) throws IOException; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/YarException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar; 15 | 16 | import java.io.Serializable; 17 | 18 | public class YarException extends RuntimeException implements Serializable { 19 | 20 | private static final long serialVersionUID = -8940458039636061045L; 21 | 22 | public YarException(String message) { 23 | super(message); 24 | } 25 | public YarException(String message, Throwable cause) { 26 | super(message, cause); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/packager/JsonPackager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.packager; 15 | 16 | import com.fasterxml.jackson.databind.ObjectMapper; 17 | 18 | import java.io.IOException; 19 | 20 | public class JsonPackager implements Packager { 21 | 22 | private ObjectMapper objectMapper = new ObjectMapper(); 23 | 24 | 25 | public JsonPackager() { 26 | objectMapper = new ObjectMapper(); 27 | } 28 | 29 | public byte[] encode(E value) throws IOException { 30 | return objectMapper.writeValueAsBytes(value); 31 | } 32 | 33 | public E decode(byte[] data, Class messageType) throws IOException { 34 | return objectMapper.readValue(data, messageType); 35 | } 36 | 37 | public ObjectMapper getObjectMapper() { 38 | return objectMapper; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/packager/PackagerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.packager; 15 | 16 | public class PackagerFactory { 17 | 18 | /** 19 | * Create a new packager by name 20 | * 21 | * @param packagerName 22 | * @return 23 | */ 24 | public static Packager createPackager(String packagerName) { 25 | if (packagerName == null) { 26 | throw new IllegalArgumentException("Packager name should not be null."); 27 | } 28 | if (packagerName.equalsIgnoreCase("PHP")) { 29 | return new PherializePackager(); 30 | } else if (packagerName.equalsIgnoreCase("JSON")) { 31 | return new JsonPackager(); 32 | } else if (packagerName.equalsIgnoreCase("MSGPACK")) { 33 | return new MsgpackPackager(); 34 | } else { 35 | throw new IllegalArgumentException("Unknown packager type " + packagerName + "."); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/yar/YarProtocolTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.weibo.yar; 17 | 18 | import java.io.IOException; 19 | 20 | import org.json.simple.JSONObject; 21 | 22 | import junit.framework.TestCase; 23 | 24 | public class YarProtocolTest extends TestCase { 25 | 26 | String methodName = "testMethod"; 27 | Object[] params = new Object[]{"123", 456, 789}; 28 | String packagerName = "JSON"; 29 | 30 | public void testProtocolYarRequest() throws IOException { 31 | YarRequest request = new YarRequest(); 32 | request.setId(45454516); 33 | request.setMethodName(methodName); 34 | request.setPackagerName(packagerName); 35 | request.setParameters(params); 36 | byte[] requestBytes = YarProtocol.toProtocolBytes(request); 37 | 38 | YarRequest newRequest = YarProtocol.buildRequest(requestBytes); 39 | assertNotNull(newRequest); 40 | assertEquals(request, newRequest); 41 | } 42 | 43 | @SuppressWarnings("unchecked") 44 | public void testProtocolYarResponse() throws IOException { 45 | YarResponse response = new YarResponse(); 46 | response.setError("eee"); 47 | response.setId(623746); 48 | response.setOutput("tt"); 49 | response.setPackagerName(packagerName); 50 | JSONObject jo = new JSONObject(); 51 | jo.put("k1", "v1"); 52 | jo.put("k2", "v2"); 53 | response.setRet(jo); 54 | response.setStatus("0"); 55 | 56 | byte[] responseBytes = YarProtocol.toProtocolBytes(response); 57 | 58 | YarResponse newResponse = YarProtocol.buildResponse(responseBytes); 59 | assertNotNull(newResponse); 60 | assertEquals(response, newResponse); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/yarserver/HttpServerHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.yarserver; 15 | 16 | import org.json.simple.JSONObject; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.Unpooled; 20 | import io.netty.channel.ChannelHandlerContext; 21 | import io.netty.channel.SimpleChannelInboundHandler; 22 | import io.netty.handler.codec.http.DefaultFullHttpResponse; 23 | import io.netty.handler.codec.http.FullHttpRequest; 24 | import io.netty.handler.codec.http.FullHttpResponse; 25 | import io.netty.handler.codec.http.HttpHeaders; 26 | import io.netty.handler.codec.http.HttpHeaders.Values; 27 | import io.netty.handler.codec.http.HttpResponseStatus; 28 | import io.netty.handler.codec.http.HttpVersion; 29 | 30 | import com.weibo.yar.YarProtocol; 31 | import com.weibo.yar.YarRequest; 32 | import com.weibo.yar.YarResponse; 33 | 34 | public class HttpServerHandler extends SimpleChannelInboundHandler { 35 | 36 | @Override 37 | protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { 38 | 39 | ByteBuf buf = msg.content(); 40 | byte[] bytes = new byte[buf.readableBytes()]; 41 | buf.getBytes(0, bytes); 42 | 43 | YarRequest yarRequest = YarProtocol.buildRequest(bytes); 44 | YarResponse yarResponse = process(yarRequest); 45 | 46 | FullHttpResponse response = 47 | new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(YarProtocol 48 | .toProtocolBytes(yarResponse))); 49 | response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/x-www-form-urlencoded"); 50 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes()); 51 | if (HttpHeaders.isKeepAlive(msg)) { 52 | response.headers().set(HttpHeaders.Names.CONNECTION, Values.KEEP_ALIVE); 53 | } 54 | ctx.write(response); 55 | ctx.flush(); 56 | ctx.close(); 57 | } 58 | 59 | 60 | private YarResponse process(YarRequest request) { 61 | YarResponse response = new YarResponse(); 62 | response.setId(request.getId()); 63 | response.setPackagerName(request.getPackagerName()); 64 | JSONObject jo = new JSONObject(); 65 | jo.put("key", "test"); 66 | response.setRet(jo); 67 | 68 | return response; 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/yarclient/HttpYarClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.yarclient; 15 | 16 | import java.util.Map; 17 | 18 | import org.apache.commons.logging.Log; 19 | import org.apache.commons.logging.LogFactory; 20 | import org.apache.http.HttpEntity; 21 | import org.apache.http.HttpResponse; 22 | import org.apache.http.client.HttpClient; 23 | import org.apache.http.client.config.RequestConfig; 24 | import org.apache.http.client.methods.HttpPost; 25 | import org.apache.http.entity.ByteArrayEntity; 26 | import org.apache.http.entity.ContentType; 27 | import org.apache.http.impl.client.HttpClients; 28 | import org.apache.http.util.EntityUtils; 29 | 30 | 31 | 32 | public class HttpYarClient extends AbstractYarClient { 33 | private static Log log = LogFactory.getLog(HttpYarClient.class); 34 | private HttpClient httpClient = HttpClients.createDefault(); 35 | private int soTimeout; 36 | private int connectTimeout; 37 | 38 | public HttpYarClient() { 39 | this(3000, 5000); 40 | 41 | } 42 | 43 | public HttpYarClient(int soTimeout, int connectTimeout) { 44 | httpClient = HttpClients.createDefault(); 45 | this.soTimeout = soTimeout; 46 | this.connectTimeout = connectTimeout; 47 | } 48 | 49 | 50 | @Override 51 | protected byte[] httpPost(String url, Map headers, byte[] content) { 52 | RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(soTimeout).setSocketTimeout(soTimeout).setConnectTimeout(connectTimeout).build(); 53 | HttpPost httpPost = new HttpPost(url); 54 | httpPost.setConfig(requestConfig); 55 | httpPost.setEntity(new ByteArrayEntity(content, ContentType.APPLICATION_FORM_URLENCODED)); 56 | try { 57 | HttpResponse response = httpClient.execute(httpPost); 58 | int status = response.getStatusLine().getStatusCode(); 59 | if (status >= 200 && status < 300) { 60 | HttpEntity entity = response.getEntity(); 61 | return entity != null ? EntityUtils.toByteArray(entity) : null; 62 | } else { 63 | log.error("Unexpected response status: " + status); 64 | return null; 65 | } 66 | } catch (Exception e) { 67 | log.error("httpclient execute fail.", e); 68 | return null; 69 | } finally{ 70 | httpPost.releaseConnection(); 71 | } 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/yarserver/NettyYarServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.yarserver; 15 | 16 | import io.netty.bootstrap.ServerBootstrap; 17 | import io.netty.channel.ChannelFuture; 18 | import io.netty.channel.ChannelInitializer; 19 | import io.netty.channel.ChannelOption; 20 | import io.netty.channel.EventLoopGroup; 21 | import io.netty.channel.nio.NioEventLoopGroup; 22 | import io.netty.channel.socket.SocketChannel; 23 | import io.netty.channel.socket.nio.NioServerSocketChannel; 24 | import io.netty.handler.codec.http.HttpObjectAggregator; 25 | import io.netty.handler.codec.http.HttpRequestDecoder; 26 | import io.netty.handler.codec.http.HttpResponseEncoder; 27 | import io.netty.handler.stream.ChunkedWriteHandler; 28 | 29 | /** 30 | * 31 | * @Description an example for NettyYarServer 32 | * @author zhanglei 33 | * @date 2016年6月23日 34 | * 35 | */ 36 | public class NettyYarServer { 37 | 38 | public static void main(String[] args) throws Exception { 39 | NettyYarServer server = new NettyYarServer(); 40 | System.out.println("Http Server listening on 8844 ..."); 41 | server.start(8844); 42 | 43 | } 44 | 45 | public void start(int port) throws Exception { 46 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 47 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 48 | try { 49 | ServerBootstrap b = new ServerBootstrap(); 50 | b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { 51 | @Override 52 | public void initChannel(SocketChannel ch) throws Exception { 53 | ch.pipeline().addLast("http-decoder", new HttpRequestDecoder()); 54 | ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536)); 55 | ch.pipeline().addLast("http-encoder", new HttpResponseEncoder()); 56 | ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler()); 57 | ch.pipeline().addLast("serverHandler", new HttpServerHandler()); 58 | } 59 | }).option(ChannelOption.SO_BACKLOG, 1024).childOption(ChannelOption.SO_KEEPALIVE, true); 60 | 61 | ChannelFuture f = b.bind(port).sync(); 62 | 63 | f.channel().closeFuture().sync(); 64 | } finally { 65 | workerGroup.shutdownGracefully(); 66 | bossGroup.shutdownGracefully(); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/yarclient/AbstractYarClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.yarclient; 15 | 16 | import java.io.IOException; 17 | import java.util.Map; 18 | 19 | import com.weibo.yar.YarException; 20 | import com.weibo.yar.YarProtocol; 21 | import com.weibo.yar.YarRequest; 22 | import com.weibo.yar.YarResponse; 23 | 24 | /** 25 | * 26 | * @Description Abstract YarClient. 27 | * @author zhanglei28 28 | * @date 2016年5月20日 29 | * 30 | */ 31 | public abstract class AbstractYarClient implements YarClient { 32 | 33 | protected String packageName = "JSON";// default packageName 34 | 35 | public E call(String path, String method, Class responseClass, Object... parameterObject) throws IOException { 36 | return call(path, method, packageName, responseClass, parameterObject); 37 | } 38 | 39 | public E call(String path, String method, String packageName, Class responseClass, Object... parameterObject) throws IOException { 40 | byte[] requestBytes = buildRequestBtyes(generateId(), path, method, packageName, parameterObject); 41 | byte[] responseBytes = httpPost(path, null, requestBytes); 42 | E value = buildResponse(responseBytes, responseClass); 43 | return value; 44 | } 45 | 46 | protected byte[] buildRequestBtyes(String path, String method, String packageName, Object... parameterObject) throws IOException { 47 | return buildRequestBtyes(generateId(), path, method, packageName, parameterObject); 48 | } 49 | 50 | protected byte[] buildRequestBtyes(long id, String path, String method, String packageName, Object... parameterObject) 51 | throws IOException { 52 | YarRequest yarRequest = new YarRequest(id, packageName, method, parameterObject); 53 | return YarProtocol.toProtocolBytes(yarRequest); 54 | } 55 | 56 | protected E buildResponse(byte[] responseBytes, Class responseClass) throws IOException { 57 | YarResponse yarResponse = YarProtocol.buildResponse(responseBytes); 58 | if (yarResponse == null || yarResponse.getError() != null) { 59 | throw new YarException(yarResponse == null ? "yar response is null" : yarResponse.getError()); 60 | } 61 | E value = yarResponse.getValue(responseClass); 62 | return value; 63 | } 64 | 65 | protected abstract byte[] httpPost(String url, Map headers, byte[] content); 66 | 67 | protected long generateId() { 68 | // TODO common id. can override by sub class 69 | return System.currentTimeMillis(); 70 | } 71 | 72 | public String getPackageName() { 73 | return packageName; 74 | } 75 | 76 | public void setPackageName(String packageName) { 77 | this.packageName = packageName; 78 | } 79 | 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/packager/PherializePackager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.packager; 15 | 16 | import com.fasterxml.jackson.databind.ObjectMapper; 17 | import com.weibo.yar.codec.PHPUnserializer; 18 | import de.ailis.pherialize.Mixed; 19 | import de.ailis.pherialize.Pherialize; 20 | 21 | import java.io.IOException; 22 | import java.io.UnsupportedEncodingException; 23 | import java.util.ArrayList; 24 | import java.util.LinkedHashMap; 25 | import java.util.Map; 26 | 27 | /** 28 | * 29 | * @Description php serialize packager 30 | * @author chengya 31 | * @date 2016年6月7日 32 | * 33 | */ 34 | public class PherializePackager implements Packager { 35 | public byte[] encode(E value) throws IOException { 36 | return Pherialize.serialize(value).getBytes(); 37 | } 38 | 39 | public E decode(byte[] data, Class messageType) throws IOException { 40 | PHPUnserializer unserializer = new PHPUnserializer(new String(data, 0, data.length, "ISO-8859-1")); 41 | Mixed mixed = unserializer.unserializeObject(); 42 | Object o = convert(mixed); 43 | return new ObjectMapper().convertValue(o, messageType); 44 | } 45 | 46 | private Object convert(Mixed mixed) throws UnsupportedEncodingException { 47 | if(mixed == null){ 48 | return null; 49 | } 50 | Map map = new LinkedHashMap(); 51 | if (mixed.getType() != Mixed.TYPE_ARRAY) { 52 | return convertNonArray(mixed); 53 | } else { 54 | boolean flag = true; 55 | int counter = 0; 56 | for (Map.Entry entry : mixed.toArray().entrySet()) { 57 | Mixed mixedKey = (Mixed) entry.getKey(); 58 | map.put(mixedKey.toString(), convert((Mixed) entry.getValue())); 59 | if (flag) { 60 | if ((!mixedKey.isInt() && !mixedKey.isLong()) || counter++ != mixedKey.toLong()) { 61 | flag = false; 62 | } 63 | } 64 | } 65 | // convert to ArrayList if possible 66 | if (flag && map.size() > 0) { 67 | return new ArrayList(map.values()); 68 | } 69 | } 70 | 71 | return map; 72 | } 73 | 74 | private Object convertNonArray(Mixed mixed) throws UnsupportedEncodingException { 75 | switch (mixed.getType()) { 76 | case Mixed.TYPE_BOOLEAN: 77 | return mixed.toBoolean(); 78 | case Mixed.TYPE_CHAR: 79 | case Mixed.TYPE_STRING: 80 | return new String(mixed.toString().getBytes("ISO-8859-1"), "UTF-8"); 81 | case Mixed.TYPE_ARRAY: 82 | case Mixed.TYPE_UNKNOWN: 83 | // null type is TYPE_UNKNOWN 84 | if(mixed.getValue() == null){ 85 | return null; 86 | } 87 | throw new UnsupportedOperationException("unknown type: " + mixed.getType()); 88 | case Mixed.TYPE_FLOAT: 89 | case Mixed.TYPE_DOUBLE: 90 | return mixed.toDouble(); 91 | default: 92 | return mixed.toLong(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/YarRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar; 15 | 16 | 17 | 18 | import java.util.Arrays; 19 | 20 | 21 | /** 22 | * 23 | * @Description YarRequest 24 | * @author zhanglei 25 | * @date 2016年6月23日 26 | * 27 | */ 28 | public class YarRequest { 29 | private long id; 30 | private String packagerName; 31 | private String methodName; 32 | private Object[] parameters; 33 | private String requestPath; 34 | 35 | public YarRequest(String packagerName, String methodName, Object[] parameters) { 36 | super(); 37 | this.packagerName = packagerName; 38 | this.methodName = methodName; 39 | this.parameters = parameters; 40 | } 41 | 42 | public YarRequest(long id, String packagerName, String methodName, Object[] parameters) { 43 | this(packagerName, methodName, parameters); 44 | this.id = id; 45 | } 46 | 47 | public YarRequest() {} 48 | 49 | public long getId() { 50 | return id; 51 | } 52 | 53 | public void setId(long id) { 54 | this.id = id; 55 | } 56 | 57 | public String getPackagerName() { 58 | return packagerName; 59 | } 60 | 61 | public void setPackagerName(String packagerName) { 62 | this.packagerName = packagerName; 63 | } 64 | 65 | public String getMethodName() { 66 | return methodName; 67 | } 68 | 69 | public void setMethodName(String methodName) { 70 | this.methodName = methodName; 71 | } 72 | 73 | public Object[] getParameters() { 74 | return parameters; 75 | } 76 | 77 | public void setParameters(Object[] parameters) { 78 | this.parameters = parameters; 79 | } 80 | 81 | public String getRequestPath() { 82 | return requestPath; 83 | } 84 | 85 | public void setRequestPath(String requestPath) { 86 | this.requestPath = requestPath; 87 | } 88 | 89 | @Override 90 | public int hashCode() { 91 | final int prime = 31; 92 | int result = 1; 93 | result = prime * result + (int) (id ^ (id >>> 32)); 94 | result = prime * result + ((methodName == null) ? 0 : methodName.hashCode()); 95 | result = prime * result + ((packagerName == null) ? 0 : packagerName.hashCode()); 96 | result = prime * result + Arrays.hashCode(parameters); 97 | return result; 98 | } 99 | 100 | @Override 101 | public boolean equals(Object obj) { 102 | if (this == obj) return true; 103 | if (obj == null) return false; 104 | if (getClass() != obj.getClass()) return false; 105 | YarRequest other = (YarRequest) obj; 106 | if (id != other.id) return false; 107 | if (methodName == null) { 108 | if (other.methodName != null) return false; 109 | } else if (!methodName.equals(other.methodName)) return false; 110 | if (packagerName == null) { 111 | if (other.packagerName != null) return false; 112 | } else if (!packagerName.equals(other.packagerName)) return false; 113 | if (!Arrays.equals(parameters, other.parameters)) return false; 114 | return true; 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/YarHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar; 15 | 16 | import java.io.ByteArrayInputStream; 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.DataInputStream; 19 | import java.io.DataOutputStream; 20 | import java.io.IOException; 21 | 22 | /** 23 | * 24 | * @Description YarHeader 25 | * @author zhanglei 26 | * @date 2016年5月20日 27 | * 28 | */ 29 | public class YarHeader { 30 | 31 | public static final long MAGIC_NUM = 0x80DFEC60; 32 | 33 | public static final int HEADER_SIZE = 82; 34 | 35 | private long requestId = 0; 36 | 37 | private int version = 0; 38 | 39 | private long reserved = 0; 40 | 41 | private String provider = null; 42 | 43 | private String token = null; 44 | 45 | private long bodyLenght = 0; 46 | 47 | public long getRequestId() { 48 | return requestId; 49 | } 50 | 51 | public void setRequestId(long requestId) { 52 | this.requestId = requestId; 53 | } 54 | 55 | public int getVersion() { 56 | return version; 57 | } 58 | 59 | public void setVersion(int version) { 60 | this.version = version; 61 | } 62 | 63 | public long getReserved() { 64 | return reserved; 65 | } 66 | 67 | public void setReserved(long reserved) { 68 | this.reserved = reserved; 69 | } 70 | 71 | public String getProvider() { 72 | return provider; 73 | } 74 | 75 | public void setProvider(String provider) { 76 | this.provider = provider; 77 | } 78 | 79 | public String getToken() { 80 | return token; 81 | } 82 | 83 | public void setToken(String token) { 84 | this.token = token; 85 | } 86 | 87 | public long getBodyLenght() { 88 | return bodyLenght; 89 | } 90 | 91 | public void setBodyLenght(long bodyLenght) { 92 | this.bodyLenght = bodyLenght; 93 | } 94 | 95 | 96 | public static YarHeader fromBytes(byte[] bytes) throws IOException { 97 | YarHeader header = new YarHeader(); 98 | DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes)); 99 | try { 100 | header.setRequestId(in.readInt() & 0xffffffffL); 101 | header.setVersion(in.readUnsignedShort()); 102 | if (in.readInt() != MAGIC_NUM) { 103 | throw new IOException("Invalid Yar header."); 104 | } 105 | header.setReserved(in.readInt() & 0xffffffffL); 106 | byte[] tempbyte = new byte[32]; 107 | in.read(tempbyte, 0, 32); 108 | header.setProvider(new String(tempbyte)); 109 | tempbyte = new byte[32]; 110 | in.read(tempbyte, 0, 32); 111 | header.setToken(new String(tempbyte)); 112 | header.setBodyLenght(in.readInt() & 0xffffffffL); 113 | } finally { 114 | in.close(); 115 | } 116 | return header; 117 | } 118 | 119 | public byte[] toBytes() throws IOException { 120 | ByteArrayOutputStream byteStream = new ByteArrayOutputStream(HEADER_SIZE); 121 | DataOutputStream out = new DataOutputStream(byteStream); 122 | try { 123 | out.writeInt((int) getRequestId()); 124 | out.writeShort((short) getVersion()); 125 | out.writeInt((int) MAGIC_NUM); 126 | out.writeInt((int) reserved); 127 | out.write(new byte[64]); 128 | out.writeInt((int) getBodyLenght()); 129 | return byteStream.toByteArray(); 130 | } finally { 131 | byteStream.close(); 132 | out.close(); 133 | } 134 | } 135 | 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/YarResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar; 15 | 16 | import com.fasterxml.jackson.databind.MapperFeature; 17 | import com.fasterxml.jackson.databind.ObjectMapper; 18 | 19 | import java.io.IOException; 20 | 21 | /** 22 | * 23 | * @Description YarResponse 24 | * @author zhanglei 25 | * @date 2016年6月7日 26 | * 27 | */ 28 | public class YarResponse { 29 | private long id; 30 | private String status = "0"; 31 | private Object ret; 32 | private Object output; 33 | private String error; 34 | 35 | private String packagerName; 36 | 37 | public T getValue(Class contentClass) throws IOException { 38 | ObjectMapper om = new ObjectMapper(); 39 | om.configure(MapperFeature.AUTO_DETECT_IS_GETTERS, false); 40 | return om.convertValue(ret, contentClass); 41 | } 42 | 43 | public long getId() { 44 | return id; 45 | } 46 | 47 | public void setId(long id) { 48 | this.id = id; 49 | } 50 | 51 | public String getStatus() { 52 | return status; 53 | } 54 | 55 | public void setStatus(String status) { 56 | this.status = status; 57 | } 58 | 59 | public Object getRet() { 60 | return ret; 61 | } 62 | 63 | public void setRet(Object ret) { 64 | this.ret = ret; 65 | } 66 | 67 | public Object getOutput() { 68 | return output; 69 | } 70 | 71 | public void setOutput(Object output) { 72 | this.output = output; 73 | } 74 | 75 | public String getError() { 76 | return error; 77 | } 78 | 79 | public void setError(String error) { 80 | this.error = error; 81 | } 82 | 83 | public String getPackagerName() { 84 | return packagerName; 85 | } 86 | 87 | public void setPackagerName(String packagerName) { 88 | this.packagerName = packagerName; 89 | } 90 | 91 | @Override 92 | public int hashCode() { 93 | final int prime = 31; 94 | int result = 1; 95 | result = prime * result + ((error == null) ? 0 : error.hashCode()); 96 | result = prime * result + (int) (id ^ (id >>> 32)); 97 | result = prime * result + ((output == null) ? 0 : output.hashCode()); 98 | result = prime * result + ((packagerName == null) ? 0 : packagerName.hashCode()); 99 | result = prime * result + ((ret == null) ? 0 : ret.hashCode()); 100 | result = prime * result + ((status == null) ? 0 : status.hashCode()); 101 | return result; 102 | } 103 | 104 | @Override 105 | public boolean equals(Object obj) { 106 | if (this == obj) return true; 107 | if (obj == null) return false; 108 | if (getClass() != obj.getClass()) return false; 109 | YarResponse other = (YarResponse) obj; 110 | if (error == null) { 111 | if (other.error != null) return false; 112 | } else if (!error.equals(other.error)) return false; 113 | if (id != other.id) return false; 114 | if (output == null) { 115 | if (other.output != null) return false; 116 | } else if (!output.equals(other.output)) return false; 117 | if (packagerName == null) { 118 | if (other.packagerName != null) return false; 119 | } else if (!packagerName.equals(other.packagerName)) return false; 120 | if (ret == null) { 121 | if (other.ret != null) return false; 122 | } else if (!ret.equals(other.ret)) return false; 123 | if (status == null) { 124 | if (other.status != null) return false; 125 | } else if (!status.equals(other.status)) return false; 126 | return true; 127 | } 128 | 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/packager/MsgpackPackager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar.packager; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | import org.msgpack.MessagePack; 23 | import org.msgpack.MessageTypeException; 24 | import org.msgpack.packer.Packer; 25 | import org.msgpack.template.AbstractTemplate; 26 | import org.msgpack.template.ListTemplate; 27 | import org.msgpack.template.MapTemplate; 28 | import org.msgpack.template.Templates; 29 | import org.msgpack.type.ArrayValue; 30 | import org.msgpack.type.IntegerValue; 31 | import org.msgpack.type.MapValue; 32 | import org.msgpack.type.Value; 33 | import org.msgpack.unpacker.Converter; 34 | import org.msgpack.unpacker.Unpacker; 35 | 36 | /** 37 | * 38 | * @Description MsgpackPackager 39 | * @author zhanglei 40 | * @date 2016年6月7日 41 | * 42 | */ 43 | public class MsgpackPackager implements Packager { 44 | public byte[] encode(E value) throws IOException { 45 | MessagePack msgpack = new MessagePack(); 46 | return msgpack.write(value); 47 | } 48 | 49 | @SuppressWarnings({"unchecked", "rawtypes", "resource"}) 50 | public E decode(byte[] data, Class messageType) throws IOException { 51 | MessagePack msgpack = new MessagePack(); 52 | msgpack.register(Map.class, new MapTemplate(Templates.TString, new ObjectTemplate())); 53 | msgpack.register(List.class, new ListTemplate(new ObjectTemplate())); 54 | Value dynamic = msgpack.read(data); 55 | Converter converter = new Converter(msgpack, dynamic); 56 | return converter.read(messageType); 57 | } 58 | 59 | public static class ObjectTemplate extends AbstractTemplate { 60 | 61 | public void write(Packer pk, Object v, boolean required) throws IOException { 62 | if (v == null) { 63 | if (required) { 64 | throw new MessageTypeException("Attempted to write null"); 65 | } 66 | pk.writeNil(); 67 | return; 68 | } 69 | pk.write(v); 70 | } 71 | 72 | public Object read(Unpacker u, Object to, boolean required) throws IOException { 73 | if (!required && u.trySkipNil()) { 74 | return null; 75 | } 76 | 77 | return toObject(u.readValue()); 78 | } 79 | 80 | @SuppressWarnings({"rawtypes", "unchecked", "resource", "unused"}) 81 | private static Object toObject(Value value) throws IOException { 82 | Converter conv = new Converter(value); 83 | if (value.isNilValue()) { 84 | return null; 85 | } else if (value.isRawValue()) { // byte[] or String 86 | return conv.read(Templates.TString); 87 | } else if (value.isBooleanValue()) { 88 | return conv.read(Templates.TBoolean); 89 | } else if (value.isIntegerValue()) { 90 | IntegerValue intValue = value.asIntegerValue(); 91 | try { 92 | int tempInt = intValue.getInt(); 93 | return conv.read(Templates.TInteger); 94 | } catch (Exception e) {// when value is long, you got exception 95 | return conv.read(Templates.TLong); 96 | } 97 | } else if (value.isFloatValue()) { 98 | return conv.read(Templates.TDouble); 99 | } else if (value.isArrayValue()) { 100 | ArrayValue v = value.asArrayValue(); 101 | List ret = new ArrayList(v.size()); 102 | for (Value elementValue : v) { 103 | ret.add(toObject(elementValue)); 104 | } 105 | return ret; 106 | } else if (value.isMapValue()) { 107 | MapValue v = value.asMapValue(); 108 | Map map = new HashMap(v.size()); 109 | for (Map.Entry entry : v.entrySet()) { 110 | Value key = entry.getKey(); 111 | Value val = entry.getValue(); 112 | map.put(toObject(key), toObject(val)); 113 | } 114 | return map; 115 | } else { 116 | throw new RuntimeException("unknown msgpack type"); 117 | } 118 | } 119 | } 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.weibo 6 | yar-java 7 | 0.0.4-SNAPSHOT 8 | jar 9 | 10 | 11 | scm:git:https://github.com/weibocom/yar-java.git 12 | https://github.com/weibocom/yar-java 13 | scm:git:https://github.com/weibocom/yar-java.git 14 | 15 | 16 | yar-java 17 | https://github.com/weibocom/yar-java 18 | The Java yar protocol implementation 19 | 20 | 21 | UTF-8 22 | 1.7 23 | 24 | 25 | 26 | 27 | junit 28 | junit 29 | 4.5 30 | test 31 | 32 | 33 | org.apache.httpcomponents 34 | httpclient 35 | 4.3.6 36 | 37 | 38 | com.xk72 39 | pherialize 40 | 1.2.4 41 | 42 | 43 | 44 | com.fasterxml.jackson.core 45 | jackson-databind 46 | 2.10.0 47 | 48 | 49 | 50 | org.msgpack 51 | msgpack 52 | 0.6.12 53 | 54 | 55 | io.netty 56 | netty-all 57 | 4.1.42.Final 58 | 59 | 60 | 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-compiler-plugin 65 | 2.3.2 66 | 67 | ${java.source.jdk} 68 | ${java.source.jdk} 69 | ${project.build.sourceEncoding} 70 | 71 | 72 | 73 | 74 | 75 | 76 | The Apache License, Version 2.0 77 | http://www.apache.org/licenses/LICENSE-2.0.txt 78 | 79 | 80 | 81 | 82 | 83 | java8 84 | 85 | 1.8 86 | 87 | 88 | 89 | 90 | org.apache.maven.plugins 91 | maven-javadoc-plugin 92 | 93 | 94 | attach-javadocs 95 | 96 | jar 97 | 98 | 99 | -Xdoclint:none 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | release 109 | 110 | 111 | 112 | org.apache.maven.plugins 113 | maven-source-plugin 114 | 2.2.1 115 | 116 | 117 | attach-sources 118 | 119 | jar-no-fork 120 | 121 | 122 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-javadoc-plugin 127 | 2.9.1 128 | 129 | 130 | attach-javadocs 131 | 132 | jar 133 | 134 | 135 | 136 | 137 | 138 | org.apache.maven.plugins 139 | maven-gpg-plugin 140 | 1.5 141 | 142 | 143 | sign-artifacts 144 | verify 145 | 146 | sign 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | ossrh 156 | https://oss.sonatype.org/content/repositories/snapshots 157 | 158 | 159 | ossrh 160 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | Ray 169 | zzll0603@126.com 170 | Weibo 171 | 172 | 173 | half-dead 174 | dotalicious@126.com 175 | Weibo 176 | 177 | 178 | Axb 179 | uaxb@hotmail.com 180 | Weibo 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/YarProtocol.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 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 distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.weibo.yar; 15 | 16 | import java.io.ByteArrayInputStream; 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.IOException; 19 | import java.util.Arrays; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | import com.weibo.yar.packager.Packager; 25 | import com.weibo.yar.packager.PackagerFactory; 26 | 27 | /** 28 | * 29 | * @Description YarProtocol 30 | * @author zhanglei 31 | * @date 2016年6月23日 32 | * 33 | */ 34 | public class YarProtocol { 35 | 36 | public static byte[] toProtocolBytes(YarRequest request) throws IOException { 37 | if (request == null) { 38 | throw new YarException("YarRequest is null"); 39 | } 40 | Map requestMap = new HashMap(); 41 | requestMap.put("i", request.getId()); 42 | requestMap.put("m", request.getMethodName()); 43 | requestMap.put("p", Arrays.asList(request.getParameters())); 44 | String packagerName = request.getPackagerName(); 45 | return toProtocolBytes(request.getId(), packagerName, requestMap); 46 | } 47 | 48 | public static byte[] toProtocolBytes(YarResponse response) throws IOException { 49 | if (response == null) { 50 | throw new YarException("YarResponse is null"); 51 | } 52 | Map responseMap = new HashMap(); 53 | responseMap.put("i", response.getId()); 54 | responseMap.put("s", response.getStatus()); 55 | if (response.getRet() != null) { 56 | responseMap.put("r", response.getRet()); 57 | } 58 | if (response.getOutput() != null) { 59 | responseMap.put("o", response.getOutput()); 60 | } 61 | if (response.getError() != null) { 62 | responseMap.put("e", response.getError()); 63 | } 64 | 65 | String packagerName = response.getPackagerName(); 66 | return toProtocolBytes(response.getId(), packagerName, responseMap); 67 | } 68 | 69 | @SuppressWarnings("rawtypes") 70 | public static YarRequest buildRequest(byte[] requestBytes) throws IOException { 71 | if (requestBytes == null) { 72 | throw new YarException("request bytes is null"); 73 | } 74 | Map contentMap = fetchContent(requestBytes); 75 | YarRequest request = new YarRequest(); 76 | if (contentMap.containsKey("i")) { 77 | request.setId(((Number) contentMap.get("i")).longValue()); 78 | } 79 | 80 | request.setPackagerName((String) contentMap.get("ext-packagerName")); 81 | if (contentMap.containsKey("m")) { 82 | request.setMethodName((contentMap.get("m").toString())); 83 | } 84 | 85 | if (contentMap.containsKey("p")) { 86 | Object value = contentMap.get("p"); 87 | if ((value instanceof List)) { 88 | request.setParameters(((List) value).toArray()); 89 | } else if (value instanceof Map) { 90 | request.setParameters(((Map) value).values().toArray()); 91 | } 92 | } 93 | return request; 94 | } 95 | 96 | @SuppressWarnings("rawtypes") 97 | public static YarResponse buildResponse(byte[] responseBytes) throws IOException { 98 | if (responseBytes == null) { 99 | throw new YarException("response bytes is null"); 100 | } 101 | 102 | Map contentMap = fetchContent(responseBytes); 103 | 104 | YarResponse response = new YarResponse(); 105 | response.setPackagerName((String) contentMap.get("ext-packagerName")); 106 | if (contentMap.containsKey("i")) { 107 | response.setId(((Number) contentMap.get("i")).longValue()); 108 | } 109 | 110 | if (contentMap.containsKey("s")) { 111 | response.setStatus(contentMap.get("s").toString()); 112 | } 113 | 114 | if (contentMap.containsKey("o")) { 115 | response.setOutput(contentMap.get("o")); 116 | } 117 | 118 | if (contentMap.containsKey("e")) { 119 | response.setError(contentMap.get("e").toString()); 120 | } 121 | 122 | if (contentMap.containsKey("r")) { 123 | response.setRet(contentMap.get("r")); 124 | } 125 | return response; 126 | } 127 | 128 | private static byte[] toProtocolBytes(long id, String packagerName, Map params) throws IOException { 129 | Packager packager = PackagerFactory.createPackager(packagerName); 130 | 131 | byte[] bodyBytes; 132 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 133 | try { 134 | out.write(Arrays.copyOf(packagerName.toUpperCase().getBytes(), 8)); 135 | out.write(packager.encode(params)); 136 | bodyBytes = out.toByteArray(); 137 | } finally { 138 | out.close(); 139 | } 140 | 141 | YarHeader header = new YarHeader(); 142 | header.setBodyLenght(bodyBytes.length); 143 | header.setRequestId(id); 144 | ByteArrayOutputStream totalByteArrayOutputStream = new ByteArrayOutputStream(YarHeader.HEADER_SIZE + bodyBytes.length); 145 | try { 146 | totalByteArrayOutputStream.write(header.toBytes()); 147 | totalByteArrayOutputStream.write(bodyBytes); 148 | return totalByteArrayOutputStream.toByteArray(); 149 | } finally { 150 | totalByteArrayOutputStream.close(); 151 | } 152 | } 153 | 154 | @SuppressWarnings({"rawtypes", "unchecked"}) 155 | private static Map fetchContent(byte[] bytes) throws IOException { 156 | ByteArrayInputStream responseInputStream = new ByteArrayInputStream(bytes); 157 | // Read protocol header. 158 | byte[] headerBytes = new byte[YarHeader.HEADER_SIZE]; 159 | responseInputStream.read(headerBytes); 160 | YarHeader header = YarHeader.fromBytes(headerBytes); 161 | 162 | // Read 8 bytes as packager name. 163 | byte[] packagerNameBytes = new byte[8]; 164 | responseInputStream.read(packagerNameBytes); 165 | 166 | // packager name end with '\0'. 167 | int length; 168 | for (length = 0; length < packagerNameBytes.length && packagerNameBytes[length] != 0; length++); 169 | String packagerName = new String(packagerNameBytes, 0, length); 170 | 171 | // remain bytes is response content. 172 | byte[] bodyBytes = new byte[(int) (header.getBodyLenght() - 8)]; 173 | responseInputStream.read(bodyBytes); 174 | 175 | Packager packager = PackagerFactory.createPackager(packagerName); 176 | Map content = packager.decode(bodyBytes, Map.class); 177 | 178 | // ext信息 179 | content.put("ext-packagerName", packagerName); 180 | content.put("ext-protocol-header", header); 181 | return content; 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/com/weibo/yar/codec/PHPUnserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ Copyright (C) 2009 Klaus Reimer 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | package com.weibo.yar.codec; 21 | 22 | import de.ailis.pherialize.Mixed; 23 | import de.ailis.pherialize.MixedArray; 24 | import de.ailis.pherialize.Unserializer; 25 | import de.ailis.pherialize.exceptions.UnserializeException; 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | 30 | 31 | /** 32 | * Unserializes a PHP serialize format string into a Java object. 33 | * 34 | * @author Klaus Reimer (k@ailis.de) 35 | * @version $Revision$ 36 | */ 37 | 38 | public class PHPUnserializer extends Unserializer { 39 | /** 40 | * The current pointer in the data 41 | */ 42 | private int pos; 43 | 44 | /** 45 | * The data to unserialize 46 | */ 47 | private final String data; 48 | 49 | /** 50 | * The object history for resolving references 51 | */ 52 | private final List history; 53 | 54 | 55 | /** 56 | * Constructor 57 | * 58 | * @param data The data to unserialize 59 | */ 60 | 61 | public PHPUnserializer(final String data) { 62 | super(data); 63 | this.data = data; 64 | this.pos = 0; 65 | this.history = new ArrayList(); 66 | } 67 | 68 | 69 | /** 70 | * Unserializes the next object in the data stream. 71 | * 72 | * @return The unserializes object 73 | */ 74 | 75 | @Override 76 | public Mixed unserializeObject() { 77 | char type; 78 | Mixed result; 79 | 80 | type = this.data.charAt(this.pos); 81 | switch (type) { 82 | case 's': 83 | result = unserializeString(); 84 | break; 85 | 86 | case 'i': 87 | result = unserializeLong(); 88 | break; 89 | 90 | case 'd': 91 | result = unserializeDouble(); 92 | break; 93 | 94 | case 'b': 95 | result = unserializeBoolean(); 96 | break; 97 | 98 | case 'N': 99 | result = unserializeNull(); 100 | break; 101 | 102 | case 'a': 103 | return unserializeArray(); 104 | 105 | case 'R': 106 | result = unserializeReference(); 107 | break; 108 | 109 | default: 110 | throw new UnserializeException("Unable to unserialize unknown type " + type, this.pos); 111 | } 112 | 113 | this.history.add(result); 114 | return result; 115 | } 116 | 117 | 118 | /** 119 | * Unserializes the next object in the data stream into a String. 120 | * 121 | * @return The unserialized String 122 | */ 123 | 124 | private Mixed unserializeString() { 125 | int pos, length; 126 | 127 | pos = this.data.indexOf(':', this.pos + 2); 128 | length = Integer.parseInt(this.data.substring(this.pos + 2, pos)); 129 | this.pos = pos + length + 4; 130 | return new Mixed(this.data.substring(pos + 2, pos + 2 + length)); 131 | } 132 | 133 | 134 | /** 135 | * Unserializes the next object in the data stream into an Integer. 136 | * 137 | * @return The unserialized Integer 138 | */ 139 | 140 | private Mixed unserializeLong() { 141 | Long result; 142 | int pos; 143 | 144 | pos = this.data.indexOf(';', this.pos + 2); 145 | result = Long.valueOf(this.data.substring(this.pos + 2, pos)); 146 | this.pos = pos + 1; 147 | return new Mixed(result); 148 | } 149 | 150 | 151 | /** 152 | * Unserializes the next object in the data stream into an Double. 153 | * 154 | * @return The unserialized Double 155 | */ 156 | 157 | private Mixed unserializeDouble() { 158 | Double result; 159 | int pos; 160 | 161 | pos = this.data.indexOf(';', this.pos + 2); 162 | result = Double.valueOf(this.data.substring(this.pos + 2, pos)); 163 | this.pos = pos + 1; 164 | return new Mixed(result); 165 | } 166 | 167 | 168 | /** 169 | * Unserializes the next object in the data stream as a reference. 170 | * 171 | * @return The unserialized reference 172 | */ 173 | 174 | private Mixed unserializeReference() { 175 | int index; 176 | int pos; 177 | 178 | pos = this.data.indexOf(';', this.pos + 2); 179 | index = Integer.parseInt(this.data.substring(this.pos + 2, pos)); 180 | this.pos = pos + 1; 181 | return (Mixed) this.history.get(index - 1); 182 | } 183 | 184 | 185 | /** 186 | * Unserializes the next object in the data stream into a Boolean. 187 | * 188 | * @return The unserialized Boolean 189 | */ 190 | 191 | private Mixed unserializeBoolean() { 192 | Boolean result; 193 | 194 | result = Boolean.valueOf(this.data.charAt(this.pos + 2) == '1'); 195 | this.pos += 4; 196 | return new Mixed(result); 197 | } 198 | 199 | 200 | /** 201 | * Unserializes the next object in the data stream into a Null 202 | * 203 | * @return The unserialized Null 204 | */ 205 | 206 | private Mixed unserializeNull() { 207 | this.pos += 2; 208 | return null; 209 | } 210 | 211 | 212 | /** 213 | * Unserializes the next object in the data stream into an array. This method returns an 214 | * ArrayList if the unserialized array has numerical keys starting with 0 or a HashMap 215 | * otherwise. 216 | * 217 | * @return The unserialized array 218 | */ 219 | 220 | private Mixed unserializeArray() { 221 | Mixed result; 222 | MixedArray array; 223 | int pos; 224 | int max; 225 | int i; 226 | Object key, value; 227 | 228 | pos = this.data.indexOf(':', this.pos + 2); 229 | max = Integer.parseInt(this.data.substring(this.pos + 2, pos)); 230 | this.pos = pos + 2; 231 | array = new MixedArray(max); 232 | result = new Mixed(array); 233 | this.history.add(result); 234 | for (i = 0; i < max; i++) { 235 | key = unserializeObject(); 236 | this.history.remove(this.history.size() - 1); 237 | value = unserializeObject(); 238 | array.put(key, value); 239 | } 240 | this.pos++; 241 | return result; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/yar/packager/BasePackagerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2016 Weibo, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.weibo.yar.packager; 17 | 18 | import java.util.ArrayList; 19 | import java.util.HashMap; 20 | import java.util.Iterator; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.Map.Entry; 24 | 25 | import junit.framework.TestCase; 26 | /** 27 | * 28 | * @Description BasePackagerTest 29 | * @author zhanglei 30 | * @date 2016年6月7日 31 | * 32 | */ 33 | public class BasePackagerTest extends TestCase{ 34 | protected Packager packager; 35 | protected void setUp() throws Exception { 36 | packager = new JsonPackager(); 37 | super.setUp(); 38 | } 39 | 40 | protected void tearDown() throws Exception { 41 | super.tearDown(); 42 | } 43 | 44 | public void testString() throws Exception{ 45 | String org = "testString"; 46 | validate(org, String.class); 47 | } 48 | 49 | public void testInt() throws Exception{ 50 | int i = 20; 51 | validate(i, int.class); 52 | 53 | Integer integer = new Integer(20); 54 | validate(integer, Integer.class); 55 | } 56 | 57 | public void testLong() throws Exception{ 58 | long l = 1234l; 59 | validate(l, long.class); 60 | 61 | Long longNum = new Long(7987); 62 | validate(longNum, Long.class); 63 | 64 | } 65 | 66 | public void testFloat() throws Exception{ 67 | float f = 0.15f; 68 | validate(f, float.class); 69 | 70 | Float floatNum = new Float(0.22); 71 | validate(floatNum, Float.class); 72 | } 73 | 74 | public void testDouble() throws Exception{ 75 | double d = 2.33d; 76 | validate(d, double.class); 77 | 78 | Double doubleNum = new Double(3.55); 79 | validate(doubleNum, Double.class); 80 | } 81 | 82 | public void testBoolean() throws Exception{ 83 | boolean b = true; 84 | validate(b, boolean.class); 85 | 86 | Boolean bool = Boolean.TRUE; 87 | validate(bool, Boolean.class); 88 | } 89 | 90 | public void testNull() throws Exception{ 91 | Object o = null; 92 | byte[] encodeBytes = packager.encode(o); 93 | assertNotNull(encodeBytes); 94 | Object temp = packager.decode(encodeBytes, Object.class); 95 | assertNull(temp); 96 | } 97 | 98 | public void testList() throws Exception{ 99 | List list = new ArrayList(); 100 | list.add(123); 101 | list.add(465l); 102 | list.add(0.23f); 103 | list.add(3.45d); 104 | list.add(true); 105 | list.add(null); 106 | validate(list, ArrayList.class); 107 | } 108 | 109 | //只保证支持字符做key 110 | public void testMap() throws Exception{ 111 | Map map = new HashMap(); 112 | map.put("test", 123); 113 | map.put("test1", 0.23f); 114 | 115 | map.put("test2", "tt"); 116 | map.put("test3", true); 117 | map.put("test4", 777l); 118 | map.put("test5", null); 119 | validate(map, Map.class); 120 | 121 | } 122 | 123 | @SuppressWarnings({"rawtypes", "unchecked"}) 124 | public void testComplex() throws Exception{ 125 | List list = new ArrayList(); 126 | list.add("testlist"); 127 | list.add(234234); 128 | list.add(false); 129 | 130 | Map map = new HashMap(); 131 | map.put("tt", 123); 132 | 133 | List templist = new ArrayList(); 134 | templist.add(798798); 135 | templist.add("jsdlkjf"); 136 | templist.add(true); 137 | map.put("list", templist); 138 | 139 | list.add(map); 140 | validate(list, ArrayList.class); 141 | } 142 | 143 | @SuppressWarnings({"unchecked", "rawtypes"}) 144 | public void validate(Object orgValue, Class valueClazz) throws Exception{ 145 | byte[] encodeBytes = packager.encode(orgValue); 146 | assertNotNull(encodeBytes); 147 | Object temp = packager.decode(encodeBytes, valueClazz); 148 | assertNotNull(temp); 149 | assertTrue(objectEquals(orgValue, temp)); 150 | } 151 | 152 | 153 | 154 | public static boolean objectEquals(Object target, Object actual){ 155 | if(target == null && actual == null){ 156 | return true; 157 | } 158 | if(target == null || actual == null){ 159 | return false; 160 | } 161 | if(target instanceof List){ 162 | return listEquals(target, actual); 163 | }else if(target instanceof Map){ 164 | return mapEquals(target, actual); 165 | } else { 166 | return primitiveEquals(target, actual); 167 | } 168 | } 169 | 170 | 171 | 172 | private static boolean primitiveEquals(Object target, Object actual) { 173 | if(target.equals(actual)){ 174 | return true; 175 | }else{ 176 | if(target instanceof Long){ 177 | if(((Long) target).longValue() == ((Number)actual).longValue()){ 178 | return true; 179 | } 180 | } else if((target instanceof Integer)){ 181 | if(((Integer) target).intValue() == ((Number)actual).intValue()){ 182 | return true; 183 | } 184 | } else if(target instanceof Double){ 185 | if(((Double) target).doubleValue() == ((Number)actual).doubleValue()){ 186 | return true; 187 | } 188 | }else if(target instanceof Float){ 189 | if(((Float) target).floatValue() == ((Number)actual).floatValue()){ 190 | return true; 191 | } 192 | }else{ 193 | return false; 194 | } 195 | 196 | } 197 | 198 | return true; 199 | } 200 | 201 | @SuppressWarnings({"rawtypes", "unchecked"}) 202 | private static boolean mapEquals(Object target, Object actual) { 203 | assertTrue(target instanceof Map); 204 | assertTrue(actual instanceof Map); 205 | 206 | Map map1 = (Map) target; 207 | Map map2 = (Map) actual; 208 | if(map1.size() != map2.size()){ 209 | return false; 210 | } 211 | 212 | Iterator i = map1.entrySet().iterator(); 213 | while (i.hasNext()) { 214 | Entry e = i.next(); 215 | Object key = e.getKey(); 216 | Object value = e.getValue(); 217 | if (value == null) { 218 | if (!(map2.containsKey(key) && map2.get(key)==null)) 219 | return false; 220 | } else { 221 | if (!objectEquals(value, map2.get(key))) 222 | return false; 223 | } 224 | } 225 | return true; 226 | } 227 | 228 | @SuppressWarnings("rawtypes") 229 | private static boolean listEquals(Object target, Object actual) { 230 | assertTrue(target instanceof List); 231 | assertTrue(actual instanceof List); 232 | 233 | List list1 = (List) target; 234 | List list2 = (List) actual; 235 | if(list1.size() != list2.size()){ 236 | return false; 237 | } 238 | 239 | for(int i = 0; i< list1.size(); i ++){ 240 | if(!objectEquals(list1.get(i), list2.get(i))){ 241 | return false; 242 | } 243 | } 244 | return true; 245 | } 246 | 247 | 248 | } 249 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------