001/*
002 *   Licensed to the Apache Software Foundation (ASF) under one
003 *   or more contributor license agreements.  See the NOTICE file
004 *   distributed with this work for additional information
005 *   regarding copyright ownership.  The ASF licenses this file
006 *   to you under the Apache License, Version 2.0 (the
007 *   "License"); you may not use this file except in compliance
008 *   with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *   Unless required by applicable law or agreed to in writing,
013 *   software distributed under the License is distributed on an
014 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *   KIND, either express or implied.  See the License for the
016 *   specific language governing permissions and limitations
017 *   under the License.
018 *
019 */
020
021package org.apache.james.rrt.lib;
022
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.Iterator;
027import java.util.StringTokenizer;
028
029import org.apache.james.rrt.lib.Mapping.Type;
030
031import com.google.common.base.Function;
032import com.google.common.base.Joiner;
033import com.google.common.base.MoreObjects;
034import com.google.common.base.Objects;
035import com.google.common.base.Optional;
036import com.google.common.base.Preconditions;
037import com.google.common.base.Predicate;
038import com.google.common.base.Predicates;
039import com.google.common.collect.FluentIterable;
040import com.google.common.collect.ImmutableList;
041import com.google.common.collect.Iterables;
042import com.google.common.collect.Lists;
043
044public class MappingsImpl implements Mappings, Serializable {
045
046    private static final long serialVersionUID = 1L;
047
048    public static MappingsImpl empty() {
049        return builder().build();
050    }
051    
052    public static MappingsImpl fromRawString(String raw) {
053        return fromCollection(mappingToCollection(raw));
054    }
055    
056    private static ArrayList<String> mappingToCollection(String rawMapping) {
057        ArrayList<String> map = new ArrayList<String>();
058        StringTokenizer tokenizer = new StringTokenizer(rawMapping, RecipientRewriteTableUtil.getSeparator(rawMapping));
059        while (tokenizer.hasMoreTokens()) {
060            final String raw = tokenizer.nextToken().trim();
061            map.add(raw);
062        }
063        return map;
064    }
065    
066    public static MappingsImpl fromCollection(Collection<String> mappings) {
067        Builder builder = builder();
068        for (String mapping: mappings) {
069            builder.add(mapping);
070        }
071        return builder.build();
072    }
073    
074    public static MappingsImpl fromMappings(Iterable<Mapping> mappings) {
075        Builder builder = builder();
076        for (Mapping mapping: mappings) {
077            builder.add(mapping);
078        }
079        return builder.build();
080    }
081    
082    public static Builder from(Mappings from) {
083        Builder builder = new Builder();
084        builder.addAll(from);
085        return builder;
086    }
087
088    public static Builder builder() {
089        return new Builder();
090    }
091    
092    public static class Builder {
093        
094        private final ImmutableList.Builder<Mapping> mappings;
095        
096        private Builder() {
097            mappings = ImmutableList.builder();
098        }
099
100        public Builder add(String mapping) {
101            return add(MappingImpl.of(mapping));
102        }
103
104        public Builder add(Mapping mapping) {
105            mappings.add(mapping);
106            return this;
107        }
108
109        
110        public Builder addAll(Mappings mappings) {
111            this.mappings.addAll(mappings);
112            return this;
113        }
114        
115        public MappingsImpl build() {
116            return new MappingsImpl(mappings.build());
117        }
118        
119    }
120    
121    private final ImmutableList<Mapping> mappings;
122
123    private MappingsImpl(Collection<Mapping> mappings) {
124        this.mappings = ImmutableList.copyOf(mappings);
125    }
126    
127    @Override
128    public Iterable<String> asStrings() {
129        return FluentIterable.from(mappings).transform(new Function<Mapping, String>() {
130            @Override
131            public String apply(Mapping input) {
132                return input.asString();
133            }
134        });
135    }
136
137    @Override
138    public boolean contains(String mapping) {
139        return mappings.contains(mapping);
140    }
141
142    @Override
143    public int size() {
144        return mappings.size();
145    }
146
147    @Override
148    public Mappings remove(String mappingAsString) {
149        MappingImpl mapping = MappingImpl.of(mappingAsString);
150        if (mappings.contains(mapping)) {
151            ArrayList<Mapping> updatedMappings = Lists.newArrayList(mappings);
152            updatedMappings.remove(mapping);
153            return new MappingsImpl(updatedMappings);
154        }
155        return this;
156    }
157
158    @Override
159    public boolean isEmpty() {
160        return mappings.isEmpty();
161    }
162    
163    @Override
164    public Iterator<Mapping> iterator() {
165        return mappings.iterator();
166    }
167    
168    @Override
169    public String serialize() {
170        return Joiner.on(';').join(asStrings());
171    }
172    
173    private Predicate<Mapping> hasType(final Mapping.Type type) {
174        return new Predicate<Mapping>() {
175            @Override
176            public boolean apply(Mapping input) {
177                return input.getType().equals(type);
178            }
179        };
180    }
181    
182    @Override
183    public boolean contains(Type type) {
184        Preconditions.checkNotNull(type);
185        return FluentIterable.from(mappings).anyMatch(hasType(type));
186    }
187    
188    @Override
189    public Mappings select(Type type) {
190        Preconditions.checkNotNull(type);
191        return fromMappings(FluentIterable.from(mappings).filter(hasType(type)));
192    }
193    
194    
195    @Override
196    public Mappings exclude(Type type) {
197        Preconditions.checkNotNull(type);
198        return fromMappings(FluentIterable.from(mappings).filter(Predicates.not(hasType(type))));
199    }
200 
201    @Override
202    public Mapping getError() {
203        Mappings errors = select(Type.Error);
204        Preconditions.checkState(!errors.isEmpty());
205        return Iterables.getFirst(errors, null);
206    }
207
208    @Override
209    public Optional<Mappings> toOptional() {
210        if (isEmpty()) {
211            return Optional.absent();
212        }
213        return Optional.<Mappings> of(this);
214    }
215
216    @Override
217    public Mappings union(Mappings mappings) {
218        Preconditions.checkState(mappings != null, "mappings is mandatory");
219        return from(this).addAll(mappings).build();
220    }
221
222    @Override
223    public int hashCode() {
224        return Objects.hashCode(mappings);
225    }
226
227    @Override
228    public boolean equals(Object obj) {
229        if (obj instanceof MappingsImpl) {
230            MappingsImpl other = (MappingsImpl) obj;
231            return Objects.equal(mappings, other.mappings);
232        }
233        return false;
234    }
235
236    @Override
237    public String toString() {
238        return MoreObjects.toStringHelper(getClass()).add("mappings", mappings).toString();
239    }
240}