001/* 002 * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 */ 020 021package org.nuxeo.connect.client.jsf; 022 023import java.io.IOException; 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Map; 028 029import javax.faces.context.FacesContext; 030import javax.faces.model.SelectItem; 031import javax.servlet.http.HttpServletRequest; 032 033import org.apache.commons.codec.binary.Base64; 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036import org.jboss.seam.ScopeType; 037import org.jboss.seam.annotations.Factory; 038import org.jboss.seam.annotations.In; 039import org.jboss.seam.annotations.Name; 040import org.jboss.seam.annotations.Scope; 041import org.jboss.seam.contexts.Contexts; 042import org.jboss.seam.faces.FacesMessages; 043import org.jboss.seam.international.StatusMessage; 044import org.nuxeo.common.utils.ExceptionUtils; 045import org.nuxeo.connect.client.status.ConnectStatusHolder; 046import org.nuxeo.connect.client.status.ConnectUpdateStatusInfo; 047import org.nuxeo.connect.client.status.SubscriptionStatusWrapper; 048import org.nuxeo.connect.connector.NuxeoClientInstanceType; 049import org.nuxeo.connect.connector.http.ConnectUrlConfig; 050import org.nuxeo.connect.data.SubscriptionStatusType; 051import org.nuxeo.connect.identity.LogicalInstanceIdentifier; 052import org.nuxeo.connect.identity.LogicalInstanceIdentifier.InvalidCLID; 053import org.nuxeo.connect.identity.LogicalInstanceIdentifier.NoCLID; 054import org.nuxeo.connect.identity.TechnicalInstanceIdentifier; 055import org.nuxeo.connect.registration.ConnectRegistrationService; 056import org.nuxeo.connect.update.PackageException; 057import org.nuxeo.connect.update.PackageUpdateService; 058import org.nuxeo.ecm.core.api.Blob; 059import org.nuxeo.ecm.core.api.CloseableFile; 060import org.nuxeo.runtime.api.Framework; 061 062/** 063 * Seam Bean to expose Connect Registration operations. 064 * <ul> 065 * <li>getting status 066 * <li>registering 067 * <li>... 068 * </ul> 069 * 070 * @author <a href="mailto:td@nuxeo.com">Thierry Delprat</a> 071 */ 072@Name("connectStatus") 073@Scope(ScopeType.CONVERSATION) 074public class ConnectStatusActionBean implements Serializable { 075 076 private static final long serialVersionUID = 1L; 077 078 public static final String CLIENT_BANNER_TYPE = "clientSideBanner"; 079 080 public static final String SERVER_BANNER_TYPE = "serverSideBanner"; 081 082 private static final Log log = LogFactory.getLog(ConnectStatusActionBean.class); 083 084 @In(create = true, required = false) 085 protected FacesMessages facesMessages; 086 087 @In(create = true, required = true, value = "appsViews") 088 protected AppCenterViewsManager appsViews; 089 090 @In(create = true) 091 protected Map<String, String> messages; 092 093 protected String CLID; 094 095 protected String token; 096 097 protected ConnectUpdateStatusInfo connectionStatusCache; 098 099 public String getRegistredCLID() throws NoCLID { 100 if (isRegistered()) { 101 return LogicalInstanceIdentifier.instance().getCLID(); 102 } else { 103 return null; 104 } 105 } 106 107 public String getCLID() { 108 return CLID; 109 } 110 111 public void setCLID(String cLID) { 112 CLID = cLID; 113 } 114 115 public String unregister() { 116 LogicalInstanceIdentifier.cleanUp(); 117 resetRegister(); 118 return null; 119 } 120 121 public List<SelectItem> getInstanceTypes() { 122 List<SelectItem> types = new ArrayList<>(); 123 for (NuxeoClientInstanceType itype : NuxeoClientInstanceType.values()) { 124 SelectItem item = new SelectItem(itype.getValue(), "label.instancetype." + itype.getValue()); 125 types.add(item); 126 } 127 return types; 128 } 129 130 protected ConnectRegistrationService getService() { 131 return Framework.getService(ConnectRegistrationService.class); 132 } 133 134 /** 135 * @since 9.2 136 */ 137 @Factory(scope = ScopeType.APPLICATION, value = "registredConnectInstance") 138 public boolean isRegistered() { 139 return getService().isInstanceRegistered(); 140 } 141 142 /** 143 * @deprecated Since 9.2, use {@link #isRegistered()} instead. 144 */ 145 @Deprecated 146 public boolean isRegistred() { 147 return isRegistered(); 148 } 149 150 protected void flushContextCache() { 151 // A4J and Event cache don't play well ... 152 Contexts.getApplicationContext().remove("registredConnectInstance"); 153 Contexts.getApplicationContext().remove("connectUpdateStatusInfo"); 154 appsViews.flushCache(); 155 } 156 157 @Factory(value = "connectServerReachable", scope = ScopeType.EVENT) 158 public boolean isConnectServerReachable() { 159 return !ConnectStatusHolder.instance().getStatus().isConnectServerUnreachable(); 160 } 161 162 public String refreshStatus() { 163 ConnectStatusHolder.instance().getStatus(true); 164 flushContextCache(); 165 return null; 166 } 167 168 public SubscriptionStatusWrapper getStatus() { 169 return ConnectStatusHolder.instance().getStatus(); 170 } 171 172 public String resetRegister() { 173 flushContextCache(); 174 return null; 175 } 176 177 public String getToken() { 178 return token; 179 } 180 181 public void setToken(String token) throws IOException, InvalidCLID { 182 if (token != null) { 183 String tokenData = new String(Base64.decodeBase64(token)); 184 String[] tokenDataLines = tokenData.split("\n"); 185 for (String line : tokenDataLines) { 186 String[] parts = line.split(":"); 187 if (parts.length > 1 && "CLID".equals(parts[0])) { 188 getService().localRegisterInstance(parts[1], " "); 189 // force refresh of connect status info 190 connectionStatusCache = null; 191 flushContextCache(); 192 ConnectStatusHolder.instance().flush(); 193 } 194 } 195 } 196 } 197 198 public String getCTID() { 199 try { 200 return TechnicalInstanceIdentifier.instance().getCTID(); 201 } catch (Exception e) { // stupid API 202 throw ExceptionUtils.runtimeException(e); 203 } 204 } 205 206 public String localRegister() { 207 try { 208 getService().localRegisterInstance(CLID, ""); 209 } catch (InvalidCLID e) { 210 facesMessages.addToControl("offline_clid", StatusMessage.Severity.WARN, 211 messages.get("label.connect.wrongCLID")); 212 } catch (IOException e) { 213 facesMessages.addToControl("offline_clid", StatusMessage.Severity.ERROR, 214 messages.get("label.connect.registrationError")); 215 log.error("Error while registering instance locally", e); 216 } 217 flushContextCache(); 218 return null; 219 } 220 221 protected Blob packageToUpload; 222 223 protected String packageFileName; 224 225 public String getPackageFileName() { 226 return packageFileName; 227 } 228 229 public void setPackageFileName(String packageFileName) { 230 this.packageFileName = packageFileName; 231 } 232 233 public Blob getPackageToUpload() { 234 return packageToUpload; 235 } 236 237 public void setPackageToUpload(Blob packageToUpload) { 238 this.packageToUpload = packageToUpload; 239 } 240 241 public void uploadPackage() throws IOException { 242 if (packageToUpload == null) { 243 facesMessages.add(StatusMessage.Severity.WARN, "label.connect.nofile"); 244 return; 245 } 246 PackageUpdateService pus = Framework.getService(PackageUpdateService.class); 247 try (CloseableFile cfile = packageToUpload.getCloseableFile()) { 248 pus.addPackage(cfile.getFile()); 249 } catch (PackageException e) { 250 log.warn(e, e); 251 facesMessages.add(StatusMessage.Severity.ERROR, 252 messages.get("label.connect.wrong.package") + ":" + e.getMessage()); 253 return; 254 } finally { 255 packageFileName = null; 256 packageToUpload = null; 257 } 258 } 259 260 public ConnectUpdateStatusInfo getDynamicConnectUpdateStatusInfo() { 261 HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); 262 String bannerType = req.getParameter("bannerType"); 263 if ("unregistered".equals(bannerType)) { 264 return ConnectUpdateStatusInfo.unregistered(); 265 } else if ("notreachable".equals(bannerType)) { 266 return ConnectUpdateStatusInfo.connectServerUnreachable(); 267 } else if ("notvalid".equals(bannerType)) { 268 return ConnectUpdateStatusInfo.notValid(); 269 } else if ("ok".equals(bannerType)) { 270 return ConnectUpdateStatusInfo.ok(); 271 } 272 return getConnectUpdateStatusInfo(); 273 } 274 275 /** 276 * @since 5.9.2 277 */ 278 @Factory(scope = ScopeType.APPLICATION, value = "connectBannerEnabled") 279 public boolean isConnectBannerEnabled() { 280 final String testerName = Framework.getProperty("org.nuxeo.ecm.tester.name"); 281 if (testerName != null && testerName.equals("Nuxeo-Selenium-Tester")) { 282 // disable banner when running selenium tests 283 return false; 284 } 285 return true; 286 } 287 288 @Factory(scope = ScopeType.APPLICATION, value = "connectUpdateStatusInfo") 289 public ConnectUpdateStatusInfo getConnectUpdateStatusInfo() { 290 if (connectionStatusCache == null) { 291 if (!isRegistered()) { 292 connectionStatusCache = ConnectUpdateStatusInfo.unregistered(); 293 } else { 294 if (isConnectBannerEnabled() && isConnectServerReachable()) { 295 if (getStatus().isError()) { 296 connectionStatusCache = ConnectUpdateStatusInfo.connectServerUnreachable(); 297 } else { 298 if (ConnectStatusHolder.instance().getStatus().status() == SubscriptionStatusType.OK) { 299 connectionStatusCache = ConnectUpdateStatusInfo.ok(); 300 } else { 301 connectionStatusCache = ConnectUpdateStatusInfo.notValid(); 302 } 303 } 304 } else { 305 connectionStatusCache = ConnectUpdateStatusInfo.connectServerUnreachable(); 306 } 307 } 308 } 309 return connectionStatusCache; 310 } 311 312 @Factory("nuxeoConnectUrl") 313 public String getConnectServerUrl() { 314 return ConnectUrlConfig.getBaseUrl(); 315 } 316 317}