View Javadoc
1   package au.gov.amsa.ihs.reader;
2   
3   import static com.google.common.base.Optional.absent;
4   import static com.google.common.base.Optional.of;
5   
6   import java.io.File;
7   import java.io.IOException;
8   import java.io.InputStream;
9   import java.util.Enumeration;
10  import java.util.Map;
11  import java.util.zip.ZipEntry;
12  import java.util.zip.ZipFile;
13  
14  import org.joda.time.DateTime;
15  
16  import com.google.common.base.Optional;
17  
18  import au.gov.amsa.ihs.model.Ship;
19  import rx.Observable;
20  import rx.Observable.OnSubscribe;
21  import rx.Subscriber;
22  
23  public class IhsReader {
24  
25      public Observable<Map<String, String>> from(InputStream is, String parentElementName) {
26          return Observable.just(is).lift(new OperatorIhsReader(parentElementName));
27      }
28  
29      public static Observable<Map<String, String>> fromZip(File file) {
30          return shipDataFilesAsInputStreamFromZip(file).lift(new OperatorIhsReader("ShipData"));
31      }
32  
33      public static Observable<Map<String, Map<String, String>>> fromZipAsMapByImo(File file) {
34          return fromZip(file).toMap(map -> map.get(Key.LRIMOShipNo.name()));
35      }
36  
37      public static Observable<Map<String, Map<String, String>>> fromZipAsMapByMmsi(File file) {
38          return fromZip(file)
39                  // only ships with an mmsi
40                  .filter(map -> map.get(Key.MaritimeMobileServiceIdentityMMSINumber.name()) != null)
41                  // as map
42                  .toMap(map -> map.get(Key.MaritimeMobileServiceIdentityMMSINumber.name()));
43      }
44  
45      private static Observable<InputStream> shipDataFilesAsInputStreamFromZip(final File file) {
46          return Observable.create(new OnSubscribe<InputStream>() {
47  
48              @Override
49              public void call(Subscriber<? super InputStream> subscriber) {
50  
51                  ZipFile zip = null;
52                  try {
53                      zip = new ZipFile(file);
54                      Enumeration<? extends ZipEntry> en = zip.entries();
55                      while (en.hasMoreElements() && !subscriber.isUnsubscribed()) {
56                          ZipEntry entry = en.nextElement();
57                          if (entry.getName().startsWith("ShipData")
58                                  && entry.getName().endsWith(".xml")) {
59                              InputStream is = zip.getInputStream(entry);
60                              System.out.println(entry.getName());
61                              subscriber.onNext(is);
62                          }
63                      }
64                      subscriber.onCompleted();
65                  } catch (Exception e) {
66                      subscriber.onError(e);
67                  } finally {
68                      try {
69                          if (zip != null)
70                              zip.close();
71                      } catch (IOException e) {
72                          // don't care
73                      }
74                  }
75              }
76  
77          });
78      }
79  
80      public static Ship toShip(Map<String, String> values) {
81          return new ShipCreator(values).buildShip();
82      }
83  
84      private static class ShipCreator {
85          private final Map<String, String> values;
86  
87          ShipCreator(Map<String, String> values) {
88              this.values = values;
89          }
90  
91          Ship buildShip() {
92              return Ship.builder().classificationSocietyCode(value("ClassificationSocietyCode"))
93                      .countryOfBuildCode(value("CountryOfBuildCode"))
94                      .yearOfBuild(toYearOfBuild(value("DateOfBuild")))
95                      .monthOfBuild(toMonthOfBuild(value("DateOfBuild"))).flagCode(value("FlagCode"))
96                      .grossTonnage(toLong(value("GrossTonnage")))
97                      .groupBeneficialOwnerCompanyCode(value("GroupBeneficialOwnerCompanyCode"))
98                      .groupBeneficialOwnerCountryOfDomicileCode(
99                              value("GroupBeneficialOwnerCountryofDomicileCode"))
100                     .imo(value("LRIMOShipNo").get())
101                     .mmsi(value("MaritimeMobileServiceIdentityMMSINumber"))
102                     .type2(value("ShiptypeLevel2")).type3(value("ShiptypeLevel3"))
103                     .type4(value("ShiptypeLevel4")).type5(value("ShiptypeLevel5"))
104                     .deadweightTonnage(toFloat(value("FormulaDWT"))).statCode5(value("StatCode5"))
105                     .lengthOverallMetres(toFloat(value("LengthOverallLOA")))
106                     .breadthMetres(toFloat(value("Breadth")))
107                     .displacementTonnage(toFloat(value("Displacement")))
108                     .draughtMetres(toFloat(value("Draught"))).speedKnots(toFloat(value("Speed")))
109                     .lastUpdateTime(toDateTime(value("LastUpdateDate"))).name(value("ShipName"))
110                     .shipBuilderCompanyCode(value("ShipbuilderCompanyCode"))
111                     // build it
112                     .build();
113         }
114 
115         private Optional<String> value(String name) {
116             String val = values.get(name);
117             if (val == null)
118                 return absent();
119             else if (val.trim().length() == 0)
120                 return absent();
121             else
122                 return Optional.fromNullable(val.trim());
123         }
124 
125     }
126 
127     private static Optional<DateTime> toDateTime(Optional<String> value) {
128         if (!value.isPresent())
129             return absent();
130         else {
131             try {
132                 return of(DateTime.parse(value.get()));
133             } catch (RuntimeException e) {
134                 return absent();
135             }
136         }
137     }
138 
139     private static Optional<Integer> toYearOfBuild(Optional<String> value) {
140         if (!value.isPresent())
141             return absent();
142         else {
143             try {
144                 return of(Integer.parseInt(value.get().substring(0, 4)));
145             } catch (RuntimeException e) {
146                 return absent();
147             }
148         }
149     }
150 
151     private static Optional<Integer> toMonthOfBuild(Optional<String> value) {
152         if (!value.isPresent())
153             return absent();
154         else {
155             int month = Integer.parseInt(value.get().substring(4, 6));
156             if (month > 0)
157                 return of(month);
158             else
159                 return absent();
160         }
161     }
162 
163     private static Optional<Long> toLong(Optional<String> value) {
164         if (!value.isPresent())
165             return Optional.absent();
166         else {
167             return Optional.of(Long.parseLong(value.get()));
168         }
169     }
170 
171     private static Optional<Float> toFloat(Optional<String> value) {
172         if (!value.isPresent())
173             return Optional.absent();
174         else {
175             return Optional.of(Float.parseFloat(value.get()));
176         }
177     }
178 
179 }