001package jmri.jmrit.logixng.actions;
002
003import java.awt.Desktop;
004import java.io.IOException;
005import java.net.*;
006import java.util.Locale;
007import java.util.Map;
008
009import jmri.InstanceManager;
010import jmri.JmriException;
011import jmri.jmrit.logixng.*;
012
013/**
014 * Executes an string action with the result of an string expression.
015 * 
016 * @author Daniel Bergqvist Copyright 2019
017 */
018public class WebBrowser
019        extends AbstractDigitalAction
020        implements FemaleSocketListener {
021
022    private String _urlExpressionSocketSystemName;
023    private final FemaleStringExpressionSocket _urlExpressionSocket;
024    
025    public WebBrowser(String sys, String user) {
026        super(sys, user);
027        _urlExpressionSocket = InstanceManager.getDefault(StringExpressionManager.class)
028                .createFemaleSocket(this, this, "E");
029    }
030    
031    @Override
032    public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException {
033        DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class);
034        String sysName = systemNames.get(getSystemName());
035        String userName = userNames.get(getSystemName());
036        if (sysName == null) sysName = manager.getAutoSystemName();
037        WebBrowser copy = new WebBrowser(sysName, userName);
038        copy.setComment(getComment());
039        return manager.registerAction(copy).deepCopyChildren(this, systemNames, userNames);
040    }
041    
042    /** {@inheritDoc} */
043    @Override
044    public Category getCategory() {
045        return Category.OTHER;
046    }
047
048    /** {@inheritDoc} */
049    @Override
050    public void execute() throws JmriException {
051        String url = _urlExpressionSocket.evaluate();
052        
053        try {
054            URI uri = new URI(url);
055            HttpURLConnection request = (HttpURLConnection) uri.toURL().openConnection();
056            request.setRequestMethod("GET");
057            request.connect();
058            if (request.getResponseCode() != 200) {
059                throw new JmriException(String.format(
060                        "Failed to connect to web page: %d, %s",
061                        request.getResponseCode(), request.getResponseMessage()));
062            }
063            if ( Desktop.getDesktop().isSupported( Desktop.Action.BROWSE) ) {
064                // Open browser to URL with draft report
065                Desktop.getDesktop().browse(uri);
066            } else {
067                throw new JmriException(String.format(
068                        "Failed to connect to web page. java.awt.Desktop doesn't suppport Action.BROWSE"));
069            }
070        } catch (IOException | URISyntaxException e) {
071            throw new JmriException(String.format(
072                    "Failed to connect to web page. Exception thrown: %s",
073                    e.getMessage()), e);
074        }
075    }
076
077    @Override
078    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
079        switch (index) {
080            case 0:
081                return _urlExpressionSocket;
082                
083            default:
084                throw new IllegalArgumentException(
085                        String.format("index has invalid value: %d", index));
086        }
087    }
088
089    @Override
090    public int getChildCount() {
091        return 1;
092    }
093
094    @Override
095    public void connected(FemaleSocket socket) {
096        if (socket == _urlExpressionSocket) {
097            _urlExpressionSocketSystemName = socket.getConnectedSocket().getSystemName();
098        } else {
099            throw new IllegalArgumentException("unkown socket");
100        }
101    }
102
103    @Override
104    public void disconnected(FemaleSocket socket) {
105        if (socket == _urlExpressionSocket) {
106            _urlExpressionSocketSystemName = null;
107        } else {
108            throw new IllegalArgumentException("unkown socket");
109        }
110    }
111
112    @Override
113    public String getShortDescription(Locale locale) {
114        return Bundle.getMessage(locale, "WebBrowser_Short");
115    }
116
117    @Override
118    public String getLongDescription(Locale locale) {
119        return Bundle.getMessage(locale, "WebBrowser_Long", _urlExpressionSocket.getName());
120    }
121
122    public FemaleStringExpressionSocket getStringExpressionSocket() {
123        return _urlExpressionSocket;
124    }
125
126    public String getStringExpressionSocketSystemName() {
127        return _urlExpressionSocketSystemName;
128    }
129
130    public void setStringExpressionSocketSystemName(String systemName) {
131        _urlExpressionSocketSystemName = systemName;
132    }
133
134    /** {@inheritDoc} */
135    @Override
136    public void setup() {
137        try {
138            if (!_urlExpressionSocket.isConnected()
139                    || !_urlExpressionSocket.getConnectedSocket().getSystemName()
140                            .equals(_urlExpressionSocketSystemName)) {
141                
142                String socketSystemName = _urlExpressionSocketSystemName;
143                
144                _urlExpressionSocket.disconnect();
145                
146                if (socketSystemName != null) {
147                    MaleSocket maleSocket =
148                            InstanceManager.getDefault(StringExpressionManager.class)
149                                    .getBySystemName(socketSystemName);
150                    if (maleSocket != null) {
151                        _urlExpressionSocket.connect(maleSocket);
152                        maleSocket.setup();
153                    } else {
154                        log.error("cannot load string expression {}", socketSystemName);
155                    }
156                }
157            } else {
158                _urlExpressionSocket.getConnectedSocket().setup();
159            }
160        } catch (SocketAlreadyConnectedException ex) {
161            // This shouldn't happen and is a runtime error if it does.
162            throw new RuntimeException("socket is already connected");
163        }
164    }
165    
166    /** {@inheritDoc} */
167    @Override
168    public void registerListenersForThisClass() {
169    }
170    
171    /** {@inheritDoc} */
172    @Override
173    public void unregisterListenersForThisClass() {
174    }
175    
176    /** {@inheritDoc} */
177    @Override
178    public void disposeMe() {
179    }
180    
181    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WebBrowser.class);
182    
183}