http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/routes/generator/xml.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/routes/generator/xml.js b/modules/control-center-web/src/main/js/routes/generator/xml.js new file mode 100644 index 0000000..079f268 --- /dev/null +++ b/modules/control-center-web/src/main/js/routes/generator/xml.js @@ -0,0 +1,736 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var _ = require('lodash'); + +var generatorUtils = require("./common"); +var dataStructures = require("../../helpers/data-structures.js"); + +exports.generateClusterConfiguration = function(cluster, clientNearConfiguration) { + var res = generatorUtils.builder(); + + res.datasources = []; + res.deep = 1; + + if (clientNearConfiguration) { + res.startBlock('<bean id="nearCacheBean" class="org.apache.ignite.configuration.NearCacheConfiguration">'); + + if (clientNearConfiguration.nearStartSize) + addProperty(res, clientNearConfiguration, 'nearStartSize'); + + if (clientNearConfiguration.nearEvictionPolicy && clientNearConfiguration.nearEvictionPolicy.kind) + createEvictionPolicy(res, clientNearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy'); + + res.endBlock('</bean>'); + + res.line(); + } + + // Generate Ignite Configuration. + res.startBlock('<bean class="org.apache.ignite.configuration.IgniteConfiguration">'); + + if (clientNearConfiguration) { + res.line('<property name="clientMode" value="true" />'); + + res.line(); + } + + // Generate discovery. + if (cluster.discovery) { + res.startBlock('<property name="discoverySpi">'); + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">'); + res.startBlock('<property name="ipFinder">'); + + var d = cluster.discovery; + + switch (d.kind) { + case 'Multicast': + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">'); + + addProperty(res, d.Multicast, 'multicastGroup'); + addProperty(res, d.Multicast, 'multicastPort'); + addProperty(res, d.Multicast, 'responseWaitTime'); + addProperty(res, d.Multicast, 'addressRequestAttempts'); + addProperty(res, d.Multicast, 'localAddress'); + + res.endBlock('</bean>'); + + break; + + case 'Vm': + if (d.Vm.addresses.length > 0) { + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">'); + + addListProperty(res, d.Vm, 'addresses'); + + res.endBlock('</bean>'); + } + else { + res.line('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder"/>'); + } + + break; + + case 'S3': + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder">'); + + if (d.S3 && d.S3.bucketName) + res.line('<property name="bucketName" value="' + escapeAttr(d.S3.bucketName) + '" />'); + + res.endBlock('</bean>'); + + break; + + case 'Cloud': + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder">'); + + addProperty(res, d.Cloud, 'credential'); + addProperty(res, d.Cloud, 'credentialPath'); + addProperty(res, d.Cloud, 'identity'); + addProperty(res, d.Cloud, 'provider'); + addListProperty(res, d.Cloud, 'regions'); + addListProperty(res, d.Cloud, 'zones'); + + res.endBlock('</bean>'); + + break; + + case 'GoogleStorage': + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder">'); + + addProperty(res, d.GoogleStorage, 'projectName'); + addProperty(res, d.GoogleStorage, 'bucketName'); + addProperty(res, d.GoogleStorage, 'serviceAccountP12FilePath'); + + //if (d.GoogleStorage.addrReqAttempts) todo ???? + // res.line('<property name="serviceAccountP12FilePath" value="' + escapeAttr(d.GoogleStorage.addrReqAttempts) + '"/>'); + + res.endBlock('</bean>'); + + break; + + case 'Jdbc': + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder">'); + res.line('<property name="initSchema" value="' + (d.Jdbc.initSchema != null || d.Jdbc.initSchema) + '"/>'); + res.endBlock('</bean>'); + + break; + + case 'SharedFs': + if (d.SharedFs.path) { + res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder">'); + addProperty(res, d.SharedFs, 'path'); + res.endBlock('</bean>'); + } + else { + res.line('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder"/>'); + } + + break; + + default: + throw "Unknown discovery kind: " + d.kind; + } + + res.endBlock('</property>'); + res.endBlock('</bean>'); + res.endBlock('</property>'); + + res.needEmptyLine = true + } + + // Generate atomics group. + addBeanWithProperties(res, cluster.atomicConfiguration, 'atomicConfiguration', + generatorUtils.atomicConfiguration.className, generatorUtils.atomicConfiguration.fields); + res.needEmptyLine = true; + + // Generate communication group. + addProperty(res, cluster, 'networkTimeout'); + addProperty(res, cluster, 'networkSendRetryDelay'); + addProperty(res, cluster, 'networkSendRetryCount'); + addProperty(res, cluster, 'segmentCheckFrequency'); + addProperty(res, cluster, 'waitForSegmentOnStart'); + addProperty(res, cluster, 'discoveryStartupDelay'); + res.needEmptyLine = true; + + // Generate deployment group. + addProperty(res, cluster, 'deploymentMode'); + res.needEmptyLine = true; + + // Generate events group. + if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) { + res.emptyLineIfNeeded(); + + res.startBlock('<property name="includeEventTypes">'); + + if (cluster.includeEventTypes.length == 1) + res.line('<util:constant static-field="org.apache.ignite.events.EventType.' + cluster.includeEventTypes[0] + '"/>'); + else { + res.startBlock('<array>'); + + for (i = 0; i < cluster.includeEventTypes.length; i++) { + if (i > 0) + res.line(); + + var eventGroup = cluster.includeEventTypes[i]; + + res.line('<!-- EventType.' + eventGroup + ' -->'); + + var eventList = dataStructures.eventGroups[eventGroup]; + + for (var k = 0; k < eventList.length; k++) { + res.line('<util:constant static-field="org.apache.ignite.events.EventType.' + eventList[k] + '"/>') + } + } + + res.endBlock('</array>'); + } + + res.endBlock('</property>'); + + res.needEmptyLine = true; + } + + // Generate marshaller group. + var marshaller = cluster.marshaller; + + if (marshaller && marshaller.kind) { + var marshallerDesc = generatorUtils.marshallers[marshaller.kind]; + + addBeanWithProperties(res, marshaller[marshaller.kind], 'marshaller', marshallerDesc.className, marshallerDesc.fields, true); + res.needEmptyLine = true; + } + + addProperty(res, cluster, 'marshalLocalJobs'); + addProperty(res, cluster, 'marshallerCacheKeepAliveTime'); + addProperty(res, cluster, 'marshallerCacheThreadPoolSize'); + res.needEmptyLine = true; + + // Generate metrics group. + addProperty(res, cluster, 'metricsExpireTime'); + addProperty(res, cluster, 'metricsHistorySize'); + addProperty(res, cluster, 'metricsLogFrequency'); + addProperty(res, cluster, 'metricsUpdateFrequency'); + res.needEmptyLine = true; + + // Generate PeerClassLoading group. + addProperty(res, cluster, 'peerClassLoadingEnabled'); + addListProperty(res, cluster, 'peerClassLoadingLocalClassPathExclude'); + addProperty(res, cluster, 'peerClassLoadingMissedResourcesCacheSize'); + addProperty(res, cluster, 'peerClassLoadingThreadPoolSize'); + res.needEmptyLine = true; + + // Generate swap group. + if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind == 'FileSwapSpaceSpi') { + addBeanWithProperties(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi', + generatorUtils.swapSpaceSpi.className, generatorUtils.swapSpaceSpi.fields, true); + + res.needEmptyLine = true; + } + + // Generate time group. + addProperty(res, cluster, 'clockSyncSamples'); + addProperty(res, cluster, 'clockSyncFrequency'); + addProperty(res, cluster, 'timeServerPortBase'); + addProperty(res, cluster, 'timeServerPortRange'); + res.needEmptyLine = true; + + // Generate thread pools group. + addProperty(res, cluster, 'publicThreadPoolSize'); + addProperty(res, cluster, 'systemThreadPoolSize'); + addProperty(res, cluster, 'managementThreadPoolSize'); + addProperty(res, cluster, 'igfsThreadPoolSize'); + res.needEmptyLine = true; + + // Generate transactions group. + addBeanWithProperties(res, cluster.transactionConfiguration, 'transactionConfiguration', + generatorUtils.transactionConfiguration.className, generatorUtils.transactionConfiguration.fields); + res.needEmptyLine = true; + + // Generate caches configs. + if (cluster.caches && cluster.caches.length > 0) { + res.emptyLineIfNeeded(); + + res.startBlock('<property name="cacheConfiguration">'); + res.startBlock('<list>'); + + for (var i = 0; i < cluster.caches.length; i++) { + if (i > 0) + res.line(); + + var cache = cluster.caches[i]; + + generateCacheConfiguration(res, cache); + } + + res.endBlock('</list>'); + res.endBlock('</property>'); + + res.needEmptyLine = true; + } + + res.endBlock('</bean>'); + + // Build final XML: + // 1. Add header. + var xml = '<?xml version="1.0" encoding="UTF-8"?>\n\n'; + + xml += '<!-- ' + generatorUtils.mainComment() + ' -->\n'; + xml += '<beans xmlns="http://www.springframework.org/schema/beans"\n'; + xml += ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n'; + xml += ' xmlns:util="http://www.springframework.org/schema/util"\n'; + xml += ' xsi:schemaLocation="http://www.springframework.org/schema/beans\n'; + xml += ' http://www.springframework.org/schema/beans/spring-beans.xsd\n'; + xml += ' http://www.springframework.org/schema/util\n'; + xml += ' http://www.springframework.org/schema/util/spring-util.xsd">\n'; + + // 2. Add external property file and all data sources. + if (res.datasources.length > 0) { + xml += ' <!-- Load external properties file. -->\n'; + xml += ' <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">\n'; + xml += ' <property name="location" value="classpath:secret.properties"/>\n'; + xml += ' </bean>\n\n'; + + xml += ' <!-- Data source beans will be initialized from external properties file. -->\n'; + + _.forEach(res.datasources, function(item) { + var beanId = item.dataSourceBean; + + xml += ' <bean id= "' + beanId + '" class="' + item.className + '">\n'; + xml += ' <property name="URL" value="${' + beanId + '.jdbc.url}" />\n'; + xml += ' <property name="user" value="${' + beanId + '.jdbc.username}" />\n'; + xml += ' <property name="password" value="${' + beanId + '.jdbc.password}" />\n'; + xml += ' </bean>\n\n'; + }); + } + + // 3. Add main content. + xml += res.join(''); + + // 4. Add footer. + xml += '</beans>\n'; + + return xml; +}; + +function createEvictionPolicy(res, evictionPolicy, propertyName) { + if (evictionPolicy && evictionPolicy.kind) { + var e = generatorUtils.evictionPolicies[evictionPolicy.kind]; + + var obj = evictionPolicy[evictionPolicy.kind.toUpperCase()]; + + addBeanWithProperties(res, obj, propertyName, e.className, e.fields, true); + } +} + +function addCacheTypeMetadataDatabaseFields(res, meta, fieldsProperty) { + var fields = meta[fieldsProperty]; + + if (fields && fields.length > 0) { + res.startBlock('<property name="' + fieldsProperty + '">'); + + res.startBlock('<list>'); + + _.forEach(fields, function (field) { + res.startBlock('<bean class="org.apache.ignite.cache.CacheTypeFieldMetadata">'); + + addProperty(res, field, 'databaseName'); + + res.startBlock('<property name="databaseType">'); + res.line('<util:constant static-field="java.sql.Types.' + field.databaseType + '"/>'); + res.endBlock('</property>'); + + addProperty(res, field, 'javaName'); + + addElement(res, 'property', 'name', 'javaType', 'value', generatorUtils.javaBuildInClass(field.javaType)); + + res.endBlock('</bean>'); + }); + + res.endBlock('</list>'); + res.endBlock('</property>'); + } +} + +function addCacheTypeMetadataQueryFields(res, meta, fieldsProperty) { + var fields = meta[fieldsProperty]; + + if (fields && fields.length > 0) { + res.startBlock('<property name="' + fieldsProperty + '">'); + + res.startBlock('<map>'); + + _.forEach(fields, function (field) { + addElement(res, 'entry', 'key', field.name, 'value', generatorUtils.javaBuildInClass(field.className)); + }); + + res.endBlock('</map>'); + + res.endBlock('</property>'); + } +} + +function addCacheTypeMetadataGroups(res, meta) { + var groups = meta.groups; + + if (groups && groups.length > 0) { + res.startBlock('<property name="groups">'); + res.startBlock('<map>'); + + _.forEach(groups, function (group) { + var fields = group.fields; + + if (fields && fields.length > 0) { + res.startBlock('<entry key="' + group.name + '">'); + res.startBlock('<map>'); + + _.forEach(fields, function (field) { + res.startBlock('<entry key="' + field.name + '">'); + + res.startBlock('<bean class="org.apache.ignite.lang.IgniteBiTuple">'); + res.line('<constructor-arg value="' + generatorUtils.javaBuildInClass(field.className) + '"/>'); + res.line('<constructor-arg value="' + field.direction + '"/>'); + res.endBlock('</bean>'); + + res.endBlock('</entry>'); + }); + + res.endBlock('</map>'); + res.endBlock('</entry>'); + } + }); + + res.endBlock('</map>'); + res.endBlock('</property>'); + } +} + +function generateCacheTypeMetadataConfiguration(res, meta) { + if (!res) + res = generatorUtils.builder(); + + res.startBlock('<bean class="org.apache.ignite.cache.CacheTypeMetadata">'); + + addProperty(res, meta, 'databaseSchema'); + addProperty(res, meta, 'databaseTable'); + + addProperty(res, meta, 'keyType'); + addProperty(res, meta, 'valueType'); + + addCacheTypeMetadataDatabaseFields(res, meta, 'keyFields'); + addCacheTypeMetadataDatabaseFields(res, meta, 'valueFields'); + + addCacheTypeMetadataQueryFields(res, meta, 'queryFields'); + addCacheTypeMetadataQueryFields(res, meta, 'ascendingFields'); + addCacheTypeMetadataQueryFields(res, meta, 'descendingFields'); + + addListProperty(res, meta, 'textFields'); + + addCacheTypeMetadataGroups(res, meta); + + res.endBlock('</bean>'); + + return res; +} + +function generateCacheConfiguration(res, cacheCfg) { + if (!res) + res = generatorUtils.builder(); + + res.startBlock('<bean class="org.apache.ignite.configuration.CacheConfiguration">'); + + addProperty(res, cacheCfg, 'name'); + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'mode', 'cacheMode'); + + addProperty(res, cacheCfg, 'atomicityMode'); + addProperty(res, cacheCfg, 'backups'); + addProperty(res, cacheCfg, 'startSize'); + addProperty(res, cacheCfg, 'readFromBackup'); + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'memoryMode'); + addProperty(res, cacheCfg, 'offHeapMaxMemory'); + addProperty(res, cacheCfg, 'swapEnabled'); + addProperty(res, cacheCfg, 'copyOnRead'); + + res.needEmptyLine = true; + + createEvictionPolicy(res, cacheCfg.evictionPolicy, 'evictionPolicy'); + + res.needEmptyLine = true; + + if (cacheCfg.nearCacheEnabled) { + res.emptyLineIfNeeded(); + + res.startBlock('<property name="nearConfiguration">'); + res.startBlock('<bean class="org.apache.ignite.configuration.NearCacheConfiguration">'); + + if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearStartSize) + addProperty(res, cacheCfg.nearConfiguration, 'nearStartSize'); + + if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearEvictionPolicy.kind) + createEvictionPolicy(res, cacheCfg.nearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy'); + + res.endBlock('</bean>'); + res.endBlock('</property>'); + } + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'sqlEscapeAll'); + addProperty(res, cacheCfg, 'sqlOnheapRowCacheSize'); + addProperty(res, cacheCfg, 'longQueryWarningTimeout'); + + if (cacheCfg.indexedTypes && cacheCfg.indexedTypes.length > 0) { + res.startBlock('<property name="indexedTypes">'); + res.startBlock('<list>'); + + for (var i = 0; i < cacheCfg.indexedTypes.length; i++) { + var pair = cacheCfg.indexedTypes[i]; + + res.line('<value>' + generatorUtils.javaBuildInClass(pair.keyClass) + '</value>'); + res.line('<value>' + generatorUtils.javaBuildInClass(pair.valueClass) + '</value>'); + } + + res.endBlock('</list>'); + res.endBlock('</property>'); + } + + addListProperty(res, cacheCfg, 'sqlFunctionClasses', 'array'); + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'rebalanceMode'); + addProperty(res, cacheCfg, 'rebalanceThreadPoolSize'); + addProperty(res, cacheCfg, 'rebalanceBatchSize'); + addProperty(res, cacheCfg, 'rebalanceOrder'); + addProperty(res, cacheCfg, 'rebalanceDelay'); + addProperty(res, cacheCfg, 'rebalanceTimeout'); + addProperty(res, cacheCfg, 'rebalanceThrottle'); + + res.needEmptyLine = true; + + if (cacheCfg.cacheStoreFactory && cacheCfg.cacheStoreFactory.kind) { + var storeFactory = cacheCfg.cacheStoreFactory[cacheCfg.cacheStoreFactory.kind]; + var data = generatorUtils.storeFactories[cacheCfg.cacheStoreFactory.kind]; + + addBeanWithProperties(res, storeFactory, 'cacheStoreFactory', data.className, data.fields, true); + + if (storeFactory.dialect) { + if (_.findIndex(res.datasources, function (ds) { + return ds.dataSourceBean == storeFactory.dataSourceBean; + }) < 0) { + res.datasources.push({ + dataSourceBean: storeFactory.dataSourceBean, + className: generatorUtils.dataSources[storeFactory.dialect] + }); + } + } + } + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'loadPreviousValue'); + addProperty(res, cacheCfg, 'readThrough'); + addProperty(res, cacheCfg, 'writeThrough'); + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'invalidate'); + addProperty(res, cacheCfg, 'defaultLockTimeout'); + addProperty(res, cacheCfg, 'transactionManagerLookupClassName'); + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'writeBehindEnabled'); + addProperty(res, cacheCfg, 'writeBehindBatchSize'); + addProperty(res, cacheCfg, 'writeBehindFlushSize'); + addProperty(res, cacheCfg, 'writeBehindFlushFrequency'); + addProperty(res, cacheCfg, 'writeBehindFlushThreadCount'); + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'statisticsEnabled'); + addProperty(res, cacheCfg, 'managementEnabled'); + + res.needEmptyLine = true; + + addProperty(res, cacheCfg, 'maxConcurrentAsyncOperations'); + + // Generate cache type metadata configs. + if ((cacheCfg.queryMetadata && cacheCfg.queryMetadata.length > 0) || + (cacheCfg.storeMetadata && cacheCfg.storeMetadata.length > 0)) { + res.emptyLineIfNeeded(); + + res.startBlock('<property name="typeMetadata">'); + res.startBlock('<list>'); + + var metaNames = []; + + if (cacheCfg.queryMetadata && cacheCfg.queryMetadata.length > 0) { + _.forEach(cacheCfg.queryMetadata, function (meta) { + if (!_.contains(metaNames, meta.name)) { + metaNames.push(meta.name); + + generateCacheTypeMetadataConfiguration(res, meta); + } + }); + } + + if (cacheCfg.storeMetadata && cacheCfg.storeMetadata.length > 0) { + _.forEach(cacheCfg.storeMetadata, function (meta) { + if (!_.contains(metaNames, meta.name)) { + metaNames.push(meta.name); + + generateCacheTypeMetadataConfiguration(res, meta); + } + }); + } + + res.endBlock('</list>'); + res.endBlock('</property>'); + } + + res.endBlock('</bean>'); + + return res; +} + +function addElement(res, tag, attr1, val1, attr2, val2) { + var elem = '<' + tag; + + if (attr1) { + elem += ' ' + attr1 + '="' + val1 + '"' + } + + if (attr2) { + elem += ' ' + attr2 + '="' + val2 + '"' + } + + elem += '/>'; + + res.emptyLineIfNeeded(); + res.line(elem); +} + +function addProperty(res, obj, propName, setterName) { + var val = obj[propName]; + + if (generatorUtils.isDefined(val)) + addElement(res, 'property', 'name', setterName ? setterName : propName, 'value', escapeAttr(val)); +} + +function addBeanWithProperties(res, bean, beanPropName, beanClass, props, createBeanAlthoughNoProps) { + if (bean && generatorUtils.hasProperty(bean, props)) { + res.emptyLineIfNeeded(); + res.startBlock('<property name="' + beanPropName + '">'); + res.startBlock('<bean class="' + beanClass + '">'); + + for (var propName in props) { + if (props.hasOwnProperty(propName)) { + var descr = props[propName]; + + if (descr) { + if (descr.type == 'list') { + addListProperty(res, bean, propName, descr.setterName); + } + else if (descr.type == 'className') { + if (bean[propName]) { + res.startBlock('<property name="' + propName + '">'); + res.line('<bean class="' + generatorUtils.knownClasses[bean[propName]].className + '"/>'); + res.endBlock('</property>'); + } + } + else if (descr.type == 'propertiesAsList') { + var val = bean[propName]; + + if (val && val.length > 0) { + res.startBlock('<property name="' + propName + '">'); + res.startBlock('<props>'); + + for (var i = 0; i < val.length; i++) { + var nameAndValue = val[i]; + + var eqIndex = nameAndValue.indexOf('='); + if (eqIndex >= 0) { + res.line('<prop key="' + escapeAttr(nameAndValue.substring(0, eqIndex)) + '">' + + + escape(nameAndValue.substr(eqIndex + 1)) + '</prop>'); + } + } + + res.endBlock('</props>'); + res.endBlock('</property>'); + } + } + else + addProperty(res, bean, propName, descr.setterName); + } + else + addProperty(res, bean, propName); + } + } + + res.endBlock('</bean>'); + res.endBlock('</property>'); + } + else if (createBeanAlthoughNoProps) { + res.emptyLineIfNeeded(); + res.line('<property name="' + beanPropName + '">'); + res.line(' <bean class="' + beanClass + '"/>'); + res.line('</property>'); + } +} +function addListProperty(res, obj, propName, listType, rowFactory) { + var val = obj[propName]; + + if (val && val.length > 0) { + res.emptyLineIfNeeded(); + + if (!listType) + listType = 'list'; + + if (!rowFactory) + rowFactory = function(val) { return '<value>' + escape(val) + '</value>' }; + + res.startBlock('<property name="' + propName + '">'); + res.startBlock('<' + listType + '>'); + + for (var i = 0; i < val.length; i++) + res.line(rowFactory(val[i])); + + res.endBlock('</' + listType + '>'); + res.endBlock('</property>'); + } +} + +function escapeAttr(s) { + if (typeof(s) != 'string') + return s; + + return s.replace(/&/g, '&').replace(/"/g, '"'); +} + +function escape(s) { + if (typeof(s) != 'string') + return s; + + return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); +}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/routes/metadata.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/routes/metadata.js b/modules/control-center-web/src/main/js/routes/metadata.js new file mode 100644 index 0000000..0af624e --- /dev/null +++ b/modules/control-center-web/src/main/js/routes/metadata.js @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var router = require('express').Router(); +var db = require('../db'); + +/* GET metadata page. */ +router.get('/', function (req, res) { + res.render('configuration/metadata'); +}); + +/** + * Get spaces and metadata accessed for user account. + * + * @param req Request. + * @param res Response. + */ +router.post('/list', function (req, res) { + var user_id = req.currentUserId(); + + // Get owned space and all accessed space. + db.Space.find({$or: [{owner: user_id}, {usedBy: {$elemMatch: {account: user_id}}}]}, function (err, spaces) { + if (err) + return res.status(500).send(err.message); + + var space_ids = spaces.map(function (value) { + return value._id; + }); + + // Get all metadata for spaces. + db.CacheTypeMetadata.find({space: {$in: space_ids}}).sort('name').exec(function (err, metadatas) { + if (err) + return res.status(500).send(err.message); + + res.json({spaces: spaces, metadatas: metadatas}); + }); + }); +}); + +/** + * Save metadata. + */ +router.post('/save', function (req, res) { + if (req.body._id) + db.CacheTypeMetadata.update({_id: req.body._id}, req.body, {upsert: true}, function (err) { + if (err) + return res.status(500).send(err.message); + + res.send(req.body._id); + }); + else { + db.CacheTypeMetadata.findOne({space: req.body.space, name: req.body.name}, function (err, metadata) { + if (err) + return res.status(500).send(err.message); + + if (metadata) + return res.status(500).send('Cache type metadata with name: "' + metadata.name + '" already exist.'); + + (new db.CacheTypeMetadata(req.body)).save(function (err, metadata) { + if (err) + return res.status(500).send(err.message); + + res.send(metadata._id); + }); + }); + } +}); + +/** + * Remove metadata by ._id. + */ +router.post('/remove', function (req, res) { + db.CacheTypeMetadata.remove(req.body, function (err) { + if (err) + return res.status(500).send(err.message); + + res.sendStatus(200); + }) +}); + +module.exports = router; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/routes/profile.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/routes/profile.js b/modules/control-center-web/src/main/js/routes/profile.js new file mode 100644 index 0000000..0269e7d --- /dev/null +++ b/modules/control-center-web/src/main/js/routes/profile.js @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var router = require('express').Router(); +var db = require('../db'); + +router.all('/profile/*', function (req, res, next) { + var userId = req.body._id; + + if (userId != req.currentUserId() && userId != req.user._id) + return res.sendStatus(403); + else + next(); +}); + +/** + * Get user profile page. + */ +router.get('/', function (req, res) { + var user_id = req.currentUserId(); + + db.Account.findById(user_id, function (err) { + if (err) + return res.status(500).send(err.message); + + res.render('settings/profile'); + }); +}); + +/** + * Save user profile. + */ +router.post('/saveUser', function (req, res) { + var params = req.body; + + if (params.newPassword) { + var newPassword = params.newPassword; + + if (!newPassword || newPassword.length == 0) + return res.status(500).send('Wrong value for new password'); + + db.Account.findById(params._id, function (err, user) { + if (err) + return res.status(500).send(err); + + user.setPassword(newPassword, function (err, updatedUser) { + if (err) + return res.status(500).send(err.message); + + if (params.userName) + updatedUser.username = params.userName; + + if (params.email) + updatedUser.email = params.email; + + updatedUser.save(function (err) { + if (err) + return res.status(500).send(err.message); + + res.json(user); + }); + }); + }); + } + else if (params.userName || params.email) { + var upd = {}; + + if (params.userName) + upd.username = params.userName; + + if (params.email) + upd.email = params.email; + + db.Account.findByIdAndUpdate(params._id, upd, {new: true}, function (err, val) { + if (err) + return res.status(500).send(err.message); + + res.json(val); + }) + } +}); + +module.exports = router; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/routes/public.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/routes/public.js b/modules/control-center-web/src/main/js/routes/public.js new file mode 100644 index 0000000..b3cb983 --- /dev/null +++ b/modules/control-center-web/src/main/js/routes/public.js @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var router = require('express').Router(); +var passport = require('passport'); +var db = require('../db'); + +// GET dropdown-menu template. +router.get('/select', function (req, res) { + res.render('templates/select', {}); +}); + +// GET dynamic tabs template. +router.get('/tab', function (req, res) { + res.render('templates/tab', {}); +}); + +// GET confirmation dialog. +router.get('/confirm', function (req, res) { + res.render('templates/confirm', {}); +}); + +// GET copy dialog. +router.get('/copy', function (req, res) { + res.render('templates/copy', {}); +}); + +/* GET login page. */ +router.get('/login', function (req, res) { + res.render('login'); +}); + +/** + * Register new account. + */ +router.post('/register', function (req, res) { + db.Account.count(function (err, cnt) { + if (err) + return res.status(401).send(err.message); + + req.body.admin = cnt == 0; + + db.Account.register(new db.Account(req.body), req.body.password, function (err, account) { + if (err) + return res.status(401).send(err.message); + + if (!account) + return res.status(500).send('Failed to create account.'); + + new db.Space({name: 'Personal space', owner: account._id}).save(); + + req.logIn(account, {}, function (err) { + if (err) + return res.status(401).send(err.message); + + return res.redirect('/configuration/clusters'); + }); + }); + }); +}); + +/** + * Login in exist account. + */ +router.post('/login', function (req, res, next) { + passport.authenticate('local', function (err, user) { + if (err) + return res.status(401).send(err.message); + + if (!user) + return res.status(401).send('Invalid email or password'); + + req.logIn(user, {}, function (err) { + if (err) + return res.status(401).send(err.message); + + res.redirect('/configuration/clusters'); + }); + })(req, res, next); +}); + +/** + * Logout. + */ +router.get('/logout', function (req, res) { + req.logout(); + + res.redirect('/'); +}); + +/* GET home page. */ +router.get('/', function (req, res) { + if (req.isAuthenticated()) + res.redirect('/configuration/clusters'); + else + res.render('index'); +}); + +///* GET sql page. */ +//router.get('/sql', function(req, res) { +// res.render('sql', { user: req.user }); +//}); +// +///* GET clients page. */ +//router.get('/clients', function(req, res) { +// res.render('clients', { user: req.user }); +//}); + +module.exports = router; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/routes/sql.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/routes/sql.js b/modules/control-center-web/src/main/js/routes/sql.js new file mode 100644 index 0000000..ce4565d --- /dev/null +++ b/modules/control-center-web/src/main/js/routes/sql.js @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var router = require('express').Router(); +var db = require('../db'); +router.get('/', function(req, res) { + res.render('sql/sql'); +}); + +module.exports = router; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/routes/summary.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/routes/summary.js b/modules/control-center-web/src/main/js/routes/summary.js new file mode 100644 index 0000000..9f8df2a --- /dev/null +++ b/modules/control-center-web/src/main/js/routes/summary.js @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var db = require('../db'); + +var router = require('express').Router(); + +var generatorXml = require('./generator/xml'); +var generatorJava = require('./generator/java'); +var generatorDocker = require('./generator/docker'); + +/* GET summary page. */ +router.get('/', function (req, res) { + res.render('configuration/summary'); +}); + +router.post('/generator', function (req, res) { + // Get cluster. + db.Cluster.findById(req.body._id).deepPopulate('caches caches.queryMetadata caches.storeMetadata').exec(function (err, cluster) { + if (err) + return res.status(500).send(err.message); + + if (!cluster) + return res.sendStatus(404); + + var clientCache = req.body.clientNearConfiguration; + + if (clientCache) + return res.send({ + xmlClient: generatorXml.generateClusterConfiguration(cluster, clientCache), + javaClient: generatorJava.generateClusterConfiguration(cluster, req.body.javaClass, clientCache) + }); + + return res.send({ + xmlServer: generatorXml.generateClusterConfiguration(cluster), + javaSnippetServer: generatorJava.generateClusterConfiguration(cluster, false), + javaClassServer: generatorJava.generateClusterConfiguration(cluster, true), + docker: generatorDocker.generateClusterConfiguration(cluster, '%OS%') + }); + }); +}); + +router.post('/download', function (req, res) { + // Get cluster. + db.Cluster.findById(req.body._id).populate('caches').exec(function (err, cluster) { + if (err) + return res.status(500).send(err.message); + + if (!cluster) + return res.sendStatus(404); + + var clientNearConfiguration = req.body.clientNearConfiguration; + + var archiver = require('archiver'); + + // Creating archive. + var zip = archiver('zip'); + + zip.on('error', function (err) { + res.status(500).send({error: err.message}); + }); + + // On stream closed we can end the request. + res.on('close', function () { + return res.status(200).send('OK').end(); + }); + + // Set the archive name. + res.attachment(cluster.name + (clientNearConfiguration ? '-client' : '') + '-configuration.zip'); + + var generatorCommon = require('./generator/common'); + + // Send the file to the page output. + zip.pipe(res); + + var javaClass = req.body.javaClass; + + if (!clientNearConfiguration) { + zip.append(generatorDocker.generateClusterConfiguration(cluster, req.body.os), {name: "Dockerfile"}); + + var props = generatorCommon.generateProperties(cluster); + + if (props) + zip.append(props, {name: "secret.properties"}); + } + + zip.append(generatorXml.generateClusterConfiguration(cluster, clientNearConfiguration), {name: cluster.name + ".xml"}) + .append(generatorJava.generateClusterConfiguration(cluster, javaClass, clientNearConfiguration), + {name: javaClass ? 'ConfigurationFactory.java' : cluster.name + '.snipplet.java'}) + .finalize(); + }); +}); + +module.exports = router; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/views/configuration/caches.jade ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/views/configuration/caches.jade b/modules/control-center-web/src/main/js/views/configuration/caches.jade new file mode 100644 index 0000000..15d8f40 --- /dev/null +++ b/modules/control-center-web/src/main/js/views/configuration/caches.jade @@ -0,0 +1,74 @@ +//- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +extends sidebar + +append scripts + script(src='/caches-controller.js') + +include ../includes/controls + +block content + .docs-header + h1 Create and Configure Ignite Caches + hr + .docs-body(ng-controller='cachesController') + +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)') + div(ng-hide='caches.length == 0') + .padding-dflt + lable.labelHeader Caches: + table.links(st-table='caches') + tbody + tr(ng-repeat='row in caches track by row._id') + td.col-sm-6(ng-class='{active: row._id == selectedItem._id}') + a(event-focus='click' event-focus-id='defaultFocusId' ng-click='selectItem(row)') {{$index + 1}}) {{row.name}}, {{row.mode | displayValue:modes:'Cache mode not set'}}, {{row.atomicityMode | displayValue:atomicities:'Cache atomicity not set'}} + .padding-top-dflt + button.btn.btn-primary(event-focus='click' event-focus-id='defaultFocusId' ng-click='createItem()') Add cache + hr + form.form-horizontal(name='inputForm' ng-if='backupItem' novalidate) + div(bs-collapse data-start-collapsed='false') + .panel.panel-default + .panel-heading + h3 + a(bs-collapse-toggle) General + .panel-collapse(bs-collapse-target) + .panel-body + .settings-row(ng-repeat='field in general') + +form-row(['col-sm-3'], ['col-sm-3']) + .panel-group(bs-collapse data-allow-multiple='true') + div(bs-collapse data-start-collapsed='true') + .panel-title(ng-show='expanded') + h3 + a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}} + .panel-collapse(bs-collapse-target) + .span(bs-collapse data-start-collapsed='true' data-allow-multiple='true') + .panel.panel-default(ng-repeat='group in advanced') + .panel-heading + h3 + a(bs-collapse-toggle) {{group.label}} + i.tipLabel.fa.fa-question-circle(ng-if='group.tip' bs-tooltip='joinTip(group.tip)' type='button') + i.tipLabel.fa.fa-question-circle.blank(ng-if='!group.tip') + .panel-collapse(bs-collapse-target) + .panel-body + .settings-row(ng-repeat='field in group.fields') + +form-row + .panel-title + h3 + a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}} + div + button.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save + button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy + button.btn.btn-primary.btn-second(ng-show='backupItem._id' ng-click='removeItem()') Remove http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/views/configuration/clusters.jade ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/views/configuration/clusters.jade b/modules/control-center-web/src/main/js/views/configuration/clusters.jade new file mode 100644 index 0000000..239a31f --- /dev/null +++ b/modules/control-center-web/src/main/js/views/configuration/clusters.jade @@ -0,0 +1,77 @@ +//- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +extends sidebar + +append scripts + script(src='/clusters-controller.js') + +include ../includes/controls + +block content + .docs-header + h1 Create and Configure Ignite Clusters + hr + .docs-body(ng-controller='clustersController') + +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)') + div(ng-hide='clusters.length == 0') + .padding-dflt + lable.labelHeader Clusters: + table.links(st-table='clusters') + tbody + tr(ng-repeat='row in clusters track by row._id') + td.col-sm-6(ng-class='{active: row._id == selectedItem._id}') + a(event-focus='click' event-focus-id='defaultFocusId' ng-click='selectItem(row)') {{$index + 1}}) {{row.name}}, {{row.discovery.kind | displayValue:discoveries:'Discovery not set'}} + .padding-top-dflt + button.btn.btn-primary(event-focus='click' event-focus-id='defaultFocusId' ng-click='createItem()')  Add cluster + label(style='margin-left: 10px; margin-right: 10px') Use template: + button.btn.btn-default.base-control(ng-init='create.template = templates[0].value' ng-model='create.template' data-template='/select' data-placeholder='Choose cluster template' bs-options='item.value as item.label for item in templates' bs-select) + i.tiplabel.fa.fa-question-circle(bs-tooltip data-title='{{joinTip(templateTip)}}' type='button') + hr + form.form-horizontal(name='inputForm' ng-if='backupItem' novalidate) + div(bs-collapse data-start-collapsed='false') + .panel.panel-default + .panel-heading + h3 + a(bs-collapse-toggle) General + .panel-collapse(bs-collapse-target) + .panel-body + .settings-row(ng-repeat='field in general') + +form-row + .panel-group(bs-collapse data-allow-multiple='true') + div(bs-collapse data-start-collapsed='true') + .panel-title(ng-show='expanded') + h3 + a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}} + .panel-collapse(bs-collapse-target) + .span(bs-collapse data-start-collapsed='true' data-allow-multiple='true') + .panel.panel-default(ng-repeat='group in advanced') + .panel-heading + h3 + a(bs-collapse-toggle) {{group.label}} + i.tipLabel.fa.fa-question-circle(ng-if='group.tip' bs-tooltip='joinTip(group.tip)' type='button') + i.tipLabel.fa.fa-question-circle.blank(ng-if='!group.tip') + .panel-collapse(bs-collapse-target) + .panel-body + .settings-row(ng-repeat='field in group.fields') + +form-row + .panel-title + h3 + a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}} + div + button.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save + button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy + button.btn.btn-primary(ng-show='backupItem._id' ng-click='removeItem()') Remove \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/views/configuration/metadata.jade ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/views/configuration/metadata.jade b/modules/control-center-web/src/main/js/views/configuration/metadata.jade new file mode 100644 index 0000000..e0cc76f --- /dev/null +++ b/modules/control-center-web/src/main/js/views/configuration/metadata.jade @@ -0,0 +1,121 @@ +//- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +extends sidebar + +append scripts + script(src='/metadata-controller.js') + +include ../includes/controls + +block content + .docs-header + h1 Create and Configure Cache Type Metadata + hr + .docs-body(ng-controller='metadataController') + +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)') + div(ng-hide='metadatas.length == 0') + .padding-dflt + lable.labelHeader Types metadata: + table.links(st-table='metadatas') + tbody + tr(ng-repeat='row in metadatas track by row._id') + td.col-sm-6(ng-class='{active: row._id == selectedItem._id}') + a(event-focus='click' event-focus-id='defaultFocusId' ng-click='selectItem(row)') {{$index + 1}}) {{row.name}} + .padding-top-dflt + button.btn.btn-primary(event-focus='click' event-focus-id='defaultFocusId' ng-click='panels.activePanel = [0]; createItem()')  Add metadata + label(style='margin-left: 6px; margin-right: 10px') For: + button.btn.btn-default(ng-model='template' data-template='/select' data-placeholder='Choose metadata type' bs-options='item.value as item.label for item in templates' bs-select) + i.tiplabel.fa.fa-question-circle(bs-tooltip data-title='{{joinTip(templateTip)}}' type='button') + hr + .panel-group(bs-collapse ng-model='panels.activePanel' data-allow-multiple='false') + .panel.panel-default(ng-show='selectedItem || backupItem') + .panel-heading + h3 + a(bs-collapse-toggle) Manual + .panel-collapse(role='tabpanel' bs-collapse-target) + .panel-body + form.form-horizontal(name='manualForm' ng-if='backupItem' novalidate) + .settings-row(ng-repeat='field in metadataManual') + +form-row + button.btn.btn-primary(ng-disabled='manualForm.$invalid' ng-click='saveItem()') Save + button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy + button.btn.btn-primary.btn-second(ng-show='backupItem._id' ng-click='removeItem()') Remove + .panel.panel-default + .panel-heading + h3 + a(bs-collapse-toggle) Load from database + .panel-collapse(bs-collapse-target) + .panel-body + form.form-horizontal(name='dbForm' novalidate) + .settings-row(ng-repeat='field in metadataDb') + +form-row + div(ng-hide='data.tables.length == 0') + table.table-bordered.table-condensed.links-edit-small-padding.col-sm-12(st-table='data.tables') + thead + tr + th.col-sm-3 Schema/Table + th Key class + th Value class + tbody + tr(ng-repeat='row in data.tables') + td(colspan='{{row.tableName ? 1 : 3}}') + div.checkbox(ng-if='!row.tableName') + label(ng-click='selectSchema($index)') + input(type='checkbox' ng-checked='row.use') + | {{row.schemaName}} + div.checkbox(ng-if='row.tableName') + label(style='padding-left: 30px' ng-click='selectTable($index)') + input(type='checkbox' ng-checked = 'row.use') + | {{row.tableName}} + td(ng-if='row.tableName') + a(ng-show='data.curTableIdx != $index' ng-click='selectTable($index)') {{row.keyClass}} + input.form-control(type='text' ng-show='data.curTableIdx == $index' ng-model='data.curKeyClass' placeholder='Key class full name') + td(ng-if='row.tableName') + a(ng-show='data.curTableIdx != $index' ng-click='selectTable($index)') {{row.valueClass}} + input.form-control(type='text' ng-show='data.curTableIdx == $index' ng-model='data.curValueClass' placeholder='Value class full name') + //div(ng-hide='data.curTableIdx < 0') + // table.table-bordered.table-condensed.links-edit-small-padding.col-sm-12(st-table='data.tables[data.curTableIdx].fields') + // thead + // tr + // th(style='width:45px') Use + // th(style='width:45px') Key + // th(style='width:45px') Ak + // th DB Name + // th DB Type + // th Java Name + // th Java Type + // tbody + // tr(ng-repeat='row in data.tables[data.curTableIdx].fields') + // td + // +dbcheck('row.use') + // td + // +dbcheck('row.key') + // td + // +dbcheck('row.ak') + // td + // label {{row.databaseName}} + // td + // label {{row.databaseType}} + // td + // a(ng-show='data.curFieldIdx != $index' ng-click='selectField($index)') {{row.javaName}} + // input.form-control(type='text' ng-show='data.curFieldIdx == $index' ng-model='data.curJavaName' placeholder='Field Java name') + // td + // a(ng-show='data.curFieldIdx != $index' ng-click='selectField($index)') {{row.javaType}} + // input.form-control(type='text' ng-show='data.curFieldIdx == $index' ng-model='data.curJavaType' placeholder='Field Java type') + button.btn.btn-primary(ng-disabled='dbForm.$invalid' ng-click='saveItem()') Save + button.btn.btn-primary.btn-second(ng-show='backupItem._id' ng-click='removeItem()') Remove + button.btn.btn-primary.btn-second(ng-click='reloadMetadata()') Reload \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/views/configuration/sidebar.jade ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/views/configuration/sidebar.jade b/modules/control-center-web/src/main/js/views/configuration/sidebar.jade new file mode 100644 index 0000000..7289f3e --- /dev/null +++ b/modules/control-center-web/src/main/js/views/configuration/sidebar.jade @@ -0,0 +1,39 @@ +//- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +extends ../templates/layout + +mixin sidebar-item(ref, num, txt) + li + a(ng-class='{active: isActive("#{ref}")}' href='#{ref}') + span.fa-stack + i.fa.fa-circle-thin.fa-stack-2x + i.fa.fa-stack-1x #{num} + | #{txt} + +block container + .row + .col-sm-2.border-right.section-left.greedy + .sidebar-nav(bs-affix) + ul.menu(ng-controller='activeLink') + +sidebar-item('/configuration/clusters', 1, 'Clusters') + +sidebar-item('/configuration/metadata', 2, 'Metadata') + +sidebar-item('/configuration/caches', 3, 'Caches') + +sidebar-item('/configuration/summary', 4, 'Summary') + + .col-sm-10.border-left.section-right + .docs-content + block content \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/views/configuration/summary.jade ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/views/configuration/summary.jade b/modules/control-center-web/src/main/js/views/configuration/summary.jade new file mode 100644 index 0000000..ba63343 --- /dev/null +++ b/modules/control-center-web/src/main/js/views/configuration/summary.jade @@ -0,0 +1,113 @@ +//- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +extends sidebar + +append scripts + script(src='/summary-controller.js') + + script(src='//cdn.jsdelivr.net/angularjs/1.3.15/angular-animate.min.js') + script(src='//cdn.jsdelivr.net/angularjs/1.3.15/angular-sanitize.min.js') + + script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/theme-chrome.js') + script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-xml.js') + script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-java.js') + script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-dockerfile.js') + +append css + +include ../includes/controls + +mixin hard-link(ref, txt) + a(style='color:#ec1c24' href=ref target='_blank') #{txt} + +block content + .docs-header + h1 Configurations Summary + hr + .docs-body(ng-controller='summaryController') + +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)') + .padding-dflt(ng-if='clusters.length == 0') + | No cluster configured. You can + a(href='clusters') configure + | it. + .padding-dflt(ng-if='clusters.length > 0') + lable.labelHeader Clusters: + table.links(st-table='clusters') + tbody + tr(ng-repeat='row in clusters track by row._id') + td.col-sm-6(ng-class='{active: row._id == selectedItem._id}') + a(ng-click='selectItem(row)') {{$index + 1}}) {{row.name}} + div(ng-show='selectedItem' role='tab' method='post' action='summary/download') + .padding-dflt(bs-collapse data-start-collapsed='false') + .panel.panel-default + form.panel-heading(role='tab' method='post' action='summary/download') + input(type='hidden' name='_id' value='{{selectedItem._id}}') + input(type='hidden' name='os' value='{{os}}') + input(type='hidden' name='javaClass' value='{{javaClassServer}}') + h3 + a(bs-collapse-toggle) Server + button.btn.btn-primary.pull-right(type='submit' style='margin-top: -5px') Download + .panel-collapse(role='tabpanel' bs-collapse-target) + div(ng-show='selectedItem' bs-tabs style='margin-top: 0.65em') + div(title='<img src="/images/xml.png" width="16px" height="16px"/> XML' bs-pane) + div(ui-ace='{ onLoad: aceInit, mode: "xml" }' ng-model='xmlServer') + div(title='<img src="/images/java.png" width="16px" height="16px"/> Java' bs-pane) + .details-row + .col-sm-1 + label Generate: + .col-sm-3 + button.form-control(type='button' ng-model='configServer.javaClassServer' bs-select data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in javaClassItems' data-sort='false') + div(ui-ace='{ onLoad: aceInit, mode: "java" }' ng-model='javaServer') + div(title='<img src="/images/docker.png" width="16px" height="16px"/> Dockerfile' bs-pane) + .details-row + p + +hard-link('https://docs.docker.com/reference/builder', 'Docker') + | file is a text file with instructions to create Docker image.<br/> + | To build image you have to store following Docker file with your Ignite XML configuration to the same directory.<br> + | Also you could use predefined + +hard-link('https://ignite.incubator.apache.org/download.html#docker', 'Apache Ignite docker image') + | . For more information about using Ignite with Docker please read + +hard-link('http://apacheignite.readme.io/docs/docker-deployment', 'documentation') + |. + .col-sm-2 + label(for='os') Operation System: + .col-sm-4 + input#os.form-control(type='text' ng-model='configServer.os' placeholder='debian:8' data-min-length='0' data-html='1' data-auto-select='true' data-animation='am-flip-x' bs-typeahead bs-options='os for os in oss') + div(ui-ace='{ onLoad: aceInit, mode: "dockerfile" }' ng-model='dockerServer') + .padding-dflt(bs-collapse data-start-collapsed='false') + .panel.panel-default + form.panel-heading(role='tab' method='post' action='summary/download') + input(type='hidden' name='_id' value='{{selectedItem._id}}') + input(type='hidden' name='javaClass' value='{{javaClassClient}}') + input(type='hidden' name='clientNearConfiguration' value='{{backupItem}}') + h3 + a(bs-collapse-toggle) Client + button.btn.btn-primary.pull-right(type='submit' style='margin-top: -5px') Download + .panel-collapse(role='tabpanel' bs-collapse-target) + div(ng-show='selectedItem') + .details-row(ng-repeat='field in clientFields') + +form-row-custom(['col-sm-3'], ['col-sm-3']) + div(bs-tabs style='margin-top: 0.65em') + div(title='<img src="/images/xml.png" width="16px" height="16px"/> XML' bs-pane) + div(ui-ace='{ onLoad: aceInit, mode: "xml" }' ng-model='xmlClient') + div(title='<img src="/images/java.png" width="16px" height="16px"/> Java' bs-pane) + .details-row + .col-sm-1 + label Generate: + .col-sm-4 + button.form-control(type='button' ng-model='backupItem.javaClassClient' bs-select data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in javaClassItems' data-sort='false') + div(ui-ace='{ onLoad: aceInit, mode: "java" }' ng-model='javaClient') http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/96522874/modules/control-center-web/src/main/js/views/error.jade ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/views/error.jade b/modules/control-center-web/src/main/js/views/error.jade new file mode 100644 index 0000000..b458fb7 --- /dev/null +++ b/modules/control-center-web/src/main/js/views/error.jade @@ -0,0 +1,22 @@ +//- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +extends templates/layout + +block container + h1= message + h2= error.status + pre #{error.stack}