Java tutorial
/* * Copyright (c) 2011-2012 by the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.dyn.net; import java.util.Arrays; import java.util.Collection; import java.util.Map; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimaps; import io.dyn.core.EventedBase; import io.dyn.core.Promise; import io.dyn.net.nio.Buffer; import org.springframework.http.MediaType; /** * @author Jon Brisbin <jon@jbrisbin.com> */ public abstract class Message<M extends Message<? super M>> extends EventedBase<M> implements Writable<Buffer, M> { protected int contentLength = 0; protected MediaType contentType; protected final ListMultimap<String, String> headers = ArrayListMultimap.create(); protected Buffer contentBuffer = new Buffer(); protected Promise<Buffer> content; public Collection<String> headers(String header) { return headers.get(header); } public String header(String header) { return first(header); } public M header(String header, String val) { return header(header, val, false); } @SuppressWarnings({ "unchecked" }) public M header(String header, String val, boolean add) { switch (header.toLowerCase()) { case "content-length": contentLength = Integer.parseInt(val); break; case "content-type": contentType = MediaType.parseMediaType(val); break; } if (add) { headers.put(header.toLowerCase(), val); } else { headers.replaceValues(header.toLowerCase(), Arrays.asList(val)); } return (M) this; } public Map<String, Collection<String>> headers() { return Multimaps.unmodifiableListMultimap(headers).asMap(); } public int contentLength() { return contentLength; } public MediaType contentType() { return contentType; } public synchronized Promise<Buffer> content() { if (null == content) { if (contentLength > 0 && contentLength == contentBuffer.remaining()) { content = Promise.wrap(contentBuffer); } else { content = new Promise<>(); } } return content; } @SuppressWarnings({ "unchecked" }) @Override public M write(Buffer buff) { contentBuffer.append(buff); if (contentLength > 0 && contentLength == contentBuffer.position()) { contentBuffer.flip(); end(); } return (M) this; } @SuppressWarnings({ "unchecked" }) public M end() { event("end"); return (M) this; } @SuppressWarnings({ "unchecked" }) public M content(Buffer buffer) { contentBuffer = buffer; if (null == content) { content = Promise.wrap(buffer); } else { this.content.result(buffer); } if (contentLength == 0 && buffer.remaining() > 0) { contentLength = contentBuffer.remaining(); } return (M) this; } private String first(String header) { Collection<String> vals = headers.get(header); if (null != vals) { if (vals.size() > 0) { return vals.iterator().next(); } } return null; } @Override public String toString() { return "Message{" + "contentLength=" + contentLength + ", headers=" + headers + ", content=" + content + '}'; } }