001/**
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 * Created on Aug 31, 2011
021 * Created by Andreas Prlic
022 *
023 * @since 3.0.2
024 */
025package org.biojava.nbio.structure.domain;
026
027import java.io.IOException;
028import java.io.InputStream;
029import java.net.MalformedURLException;
030import java.net.URL;
031import java.util.ArrayList;
032import java.util.List;
033import java.util.Map;
034import java.util.SortedSet;
035import java.util.TreeSet;
036
037import org.biojava.nbio.structure.ResidueRange;
038import org.biojava.nbio.structure.Structure;
039import org.biojava.nbio.structure.StructureException;
040import org.biojava.nbio.structure.SubstructureIdentifier;
041import org.biojava.nbio.structure.align.client.JFatCatClient;
042import org.biojava.nbio.structure.align.util.AtomCache;
043import org.biojava.nbio.structure.align.util.HTTPConnectionTools;
044import org.biojava.nbio.structure.scop.server.XMLUtil;
045import org.slf4j.Logger;
046import org.slf4j.LoggerFactory;
047
048
049/** A class that provided PDP assignments that are loaded from a remote web server
050 *
051 * @author Andreas Prlic
052 *
053 */
054public class RemotePDPProvider extends SerializableCache<String,SortedSet<String>>  implements PDPProvider{
055
056        private static final Logger logger = LoggerFactory.getLogger(RemotePDPProvider.class);
057
058        public static final String DEFAULT_SERVER = "http://source.rcsb.org/jfatcatserver/domains/";
059
060        String server = DEFAULT_SERVER;
061
062        private static String CACHE_FILE_NAME = "remotepdpdomaindefs.ser";
063
064
065        public static void main(String[] args) throws IOException, StructureException{
066                RemotePDPProvider me = new RemotePDPProvider(true);
067
068                //System.out.println(scop.getByCategory(ScopCategory.Superfamily));
069                SortedSet<String> pdpdomains = me.getPDPDomainNamesForPDB("4HHB");
070                System.out.println(pdpdomains);
071
072                AtomCache cache = new AtomCache();
073                Structure s = me.getDomain(pdpdomains.first(), cache);
074                System.out.println(s);
075
076                me.flushCache();
077
078        }
079
080
081        public RemotePDPProvider(){
082                // equivalent to this(false) but without IOException
083                super(CACHE_FILE_NAME);
084                disableCache();
085        }
086
087
088        /**
089         *
090         * @param useCache
091         * @throws IOException
092         */
093        public RemotePDPProvider(boolean useCache) throws IOException {
094
095                super(CACHE_FILE_NAME);
096
097                if ( ! useCache) {
098                        disableCache();
099                        //else if ( serializedCache.keySet().size() < 10000){
100                } else {
101                        // make sure we always have the latest assignments...
102                        loadRepresentativeDomains();
103                }
104
105        }
106
107
108
109        /** get the ranges of representative domains from the centralized server
110         * @throws IOException if the server cannot be reached
111         */
112        private void loadRepresentativeDomains() throws IOException {
113
114                AssignmentXMLSerializer results = null;
115                try {
116                        URL u = new URL(server + "getRepresentativePDPDomains");
117                        logger.info("Fetching {}",u);
118                        InputStream response = HTTPConnectionTools.getInputStream(u);
119                        String xml = JFatCatClient.convertStreamToString(response);
120                        results  = AssignmentXMLSerializer.fromXML(xml);
121
122                        Map<String,String> data = results.getAssignments();
123                        logger.info("got {} domain ranges for PDP domains from server.",data.size());
124                        for (String key: data.keySet()){
125                                String range = data.get(key);
126
127                                // work around list in results;
128
129                                String[] spl = range.split(",");
130                                SortedSet<String> value = new TreeSet<String>();
131
132                                for (String s : spl){
133                                        value.add(s);
134
135                                }
136                                serializedCache.put(key, value);
137                        }
138
139                } catch (MalformedURLException e){
140                        logger.error("Malformed PDP server: "+server,e);
141                        throw new IllegalArgumentException("Invalid Server: "+server, e);
142                }
143        }
144
145
146        public String getServer() {
147                return server;
148        }
149
150        public void setServer(String server) {
151                this.server = server;
152        }
153
154        /**
155         * Get the structure for a particular PDP domain
156         * @param pdpDomainName PDP identifier, e.g. "PDP:4HHBAa"
157         * @param cache AtomCache, responsible for fetching and storing the coordinates
158         * @return Structure representing the PDP domain
159         * @throws IOException if the server cannot be reached
160         * @throws StructureException For errors parsing the structure
161         */
162        @Override
163        public Structure getDomain(String pdpDomainName, AtomCache cache) throws IOException, StructureException {
164                return cache.getStructure(getPDPDomain(pdpDomainName));
165        }
166
167        /**
168         * Get a StructureIdentifier representing the specified PDP domain.
169         *
170         * @param pdpDomainName PDP domain name
171         * @return a PDPDomain representing this domain name
172         * @throws IOException if the server cannot be reached
173         */
174        @Override
175        public PDPDomain getPDPDomain(String pdpDomainName) throws IOException{
176                SortedSet<String> domainRanges = null;
177                if ( serializedCache != null){
178                        if ( serializedCache.containsKey(pdpDomainName)){
179                                domainRanges= serializedCache.get(pdpDomainName);
180
181                        }
182                }
183
184
185                boolean shouldRequestDomainRanges = checkDomainRanges(domainRanges);
186
187                try {
188                        if (shouldRequestDomainRanges){
189                                URL u = new URL(server + "getPDPDomain?pdpId="+pdpDomainName);
190                                logger.info("Fetching {}",u);
191                                InputStream response = HTTPConnectionTools.getInputStream(u);
192                                String xml = JFatCatClient.convertStreamToString(response);
193                                domainRanges = XMLUtil.getDomainRangesFromXML(xml);
194                                if ( domainRanges != null)
195                                        cache(pdpDomainName,domainRanges);
196                        }
197                } catch (MalformedURLException e){
198                        logger.error("Problem generating PDP request URL for "+pdpDomainName,e);
199                        throw new IllegalArgumentException("Invalid PDP name: "+pdpDomainName, e);
200                }
201
202                String pdbId = null;
203                List<ResidueRange> ranges = new ArrayList<ResidueRange>();
204                for(String domainRange : domainRanges) {
205                        SubstructureIdentifier strucId = new SubstructureIdentifier(domainRange);
206                        if(pdbId == null) {
207                                pdbId = strucId.getPdbId();
208                        } else if(!pdbId.equals(strucId.getPdbId())) {
209                                // should never happen with correct server implementation
210                                throw new RuntimeException("Don't know how to take the union of domains from multiple PDB IDs.");
211                        }
212
213                        ranges.addAll(strucId.getResidueRanges());
214                }
215                return new PDPDomain(pdpDomainName,ranges);
216        }
217
218        /** returns true if client should fetch domain definitions from server
219         *
220         * @param domainRanges
221         * @return
222         */
223        private boolean checkDomainRanges(SortedSet<String> domainRanges) {
224
225                if ( (domainRanges == null) || (domainRanges.size() == 0)){
226                        return true;
227                }
228
229                for ( String d : domainRanges){
230                        //System.out.println("domainRange: >" + d +"< " + d.length());
231                        if ( (d != null) && (d.length() >0)){
232                                return false;
233                        }
234                }
235
236                return true;
237        }
238
239        /**
240         * Get a list of all PDP domains for a given PDB entry
241         * @param pdbId PDB ID
242         * @return Set of domain names, e.g. "PDP:4HHBAa"
243         * @throws IOException if the server cannot be reached
244         */
245        @Override
246        public SortedSet<String> getPDPDomainNamesForPDB(String pdbId) throws IOException{
247                SortedSet<String> results = null;
248                try {
249                        URL u = new URL(server + "getPDPDomainNamesForPDB?pdbId="+pdbId);
250                        logger.info("Fetching {}",u);
251                        InputStream response = HTTPConnectionTools.getInputStream(u);
252                        String xml = JFatCatClient.convertStreamToString(response);
253                        results  = XMLUtil.getDomainRangesFromXML(xml);
254
255                } catch (MalformedURLException e){
256                        logger.error("Problem generating PDP request URL for "+pdbId,e);
257                        throw new IllegalArgumentException("Invalid PDB name: "+pdbId, e);
258                }
259                return results;
260        }
261}